/*******************************************************************************
**
** Function          op
**
** Description       This is interface for bluedroid stack to libbt. It exposes
**                   several functionality to bluedroid stack.
**
** Returns           0 or -1
**
*******************************************************************************/
static int op(bt_vendor_opcode_t opcode, void *param)
{
    int retval = BT_VND_OP_RESULT_SUCCESS;

    BTVNDDBG("op for %d named: %s", opcode,dump_vendor_op(opcode));
    switch(opcode)
    {
        case BT_VND_OP_POWER_CTRL:
            {
                int *state = (int *) param;
                if (*state == BT_VND_PWR_OFF)
                {
                    //moved to userial_vendor_close()since TL power control is done with IOCTL
                    //which required fd before release fd.
                }
                else if (*state == BT_VND_PWR_ON)
                {
                    //power on done after fd acquired through userial_vendor_open()
                }
            }
            break;

        case BT_VND_OP_FW_CFG:
            {
                hw_config_start();
            }
            break;

        case BT_VND_OP_SCO_CFG:
            {
#if (SCO_CFG_INCLUDED == TRUE)
                hw_sco_config();
#else
                bt_vendor_cbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
                retval = -1;
#endif
            }
            break;

        case BT_VND_OP_USERIAL_OPEN:
            {
                int (*fd_array)[] = (int (*)[]) param;
                int fd, idx;
                fd = userial_vendor_open();
#if (INTEL_HSB_PLATFORM == TRUE)
                userial_vendor_configure_serial((tUSERIAL_CFG *)&userial_init_cfg, userial_init_cfg.baud);
#endif
                if (fd != -1)
                {
                    for (idx=0; idx < CH_MAX; idx++)
                        (*fd_array)[idx] = fd;

                    retval = 1;
                }
                /* retval contains numbers of open fd of HCI channels */
                if(retval)
                {
                    if(0 < upio_set_bluetooth_power(UPIO_BT_POWER_ON))
                      retval = -1;
                    else
                      retval = 1;
                }
            }
            break;

        case BT_VND_OP_USERIAL_CONFIG:
            {
                int baud_rate = STANDARD_BAUD, rt = 0;
                bt_vendor_baud_config_t baud_config = STANDARD_BAUD;
                if (param)
                    baud_config = *((int*) param);
                if (baud_config == STANDARD_BAUD)
                    baud_rate = 115200;
                else if (baud_config == HIGHER_BAUD)
                    baud_rate = hw_operation_baud;
                rt = userial_vendor_configure_serial\
                               ((tUSERIAL_CFG *)&userial_init_cfg, \
                                        line_speed_to_userial_baud(baud_rate));

                if(rt == 0)
                {
                    BTVNDDBG("baudrate changed to :%d", baud_rate);
                }
                else
                {
                    BTVNDDBG("failed to change baudrate:%d", baud_rate);
                }
            }
            break;
#if (BT_EN_VIA_USERIAL_IOCTL == TRUE)
        case BT_VND_OP_FW_DL_COMPLETE:
            {
                unsigned long fw_cfg_result = FW_SUCCESS;
                userial_vendor_ioctl(USERIAL_OP_FW_CFG_CMPL, \
                                                    (void*)&fw_cfg_result);
            }
            break;
        case BT_VND_OP_FW_DL_STATUS:
            {
                int on = UPIO_BT_POWER_ON;
                retval = userial_vendor_ioctl(USERIAL_OP_BT_EN, &on);
                ms_delay(100);
            }
            break;
#endif
        case BT_VND_OP_USERIAL_CLOSE:
            {
                upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
                userial_vendor_close();
#ifdef BT_FM_MITIGATION
                bt_fm_deinit();
#endif
            }
            break;

        case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
            {
                uint32_t *timeout_ms = (uint32_t *) param;
                *timeout_ms = hw_lpm_get_idle_timeout();
            }
            break;

        case BT_VND_OP_LPM_SET_MODE:
            {
                uint8_t mode = *(uint8_t *) param;
                hw_lpm_enable(((mode)? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE));
            }
            break;

        case BT_VND_OP_LPM_WAKE_SET_STATE:
            {
                uint8_t *state = (uint8_t *) param;
                uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \
                                        TRUE : FALSE;
#if (INTEL_AG6XX_UART == TRUE)
                if(lpm_is_enabled)
                {
                    upio_set_bt_wake_state(wake_assert);
                }
#endif
            }
            break;
#if (LNP_LPM_ENABLED == TRUE)
        case BT_VND_OP_LPM_SET_IDLE_STATE:
            {
                if(lpm_is_enabled)
                {
                   userial_vendor_ioctl(USERIAL_OP_LPM_SET_IDLE_STATE,
                                                    (void*)param);
                }
            }
            break;
#endif
#if (HW_END_WITH_HCI_RESET == TRUE)
        case BT_VND_OP_EPILOG:
            hw_epilog_process();
            break;
#endif
#if (A2DP_OFFLOAD_INCLUDED == TRUE)
        case BT_VND_OP_A2DP_STREAM_CONFIG:
            BTVNDDBG("op: BT_VND_BT_VND_OP_A2DP_STREAM_CONFIG");
            a2dp_offload_send_stream_config((A2DP_OFFLOAD_STREAM_CFG_PARAMS *)param);
            break;
        case BT_VND_OP_A2DP_SET_STREAM_STATE:
            BTVNDDBG("op: BT_VND_OP_A2DP_SET_STREAM_STATE");
            uint8_t *state = (uint8_t *) param;
            a2dp_offload_set_stream_state(*state);
            break;
#endif
        case BT_VND_OP_SET_AUDIO_STATE:
            // do nothing
            break;
    }

    return retval;
}
/** Requested operations */
static int op(bt_vendor_opcode_t opcode, void *param)
{
    int retval = 0;

    BTVNDDBG("op for %d", opcode);

    switch(opcode)
    {
        case BT_VND_OP_POWER_CTRL:
            {
                int *state = (int *) param;
                if (*state == BT_VND_PWR_OFF)
                    upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
                else if (*state == BT_VND_PWR_ON)
                    upio_set_bluetooth_power(UPIO_BT_POWER_ON);
            }
            break;

        case BT_VND_OP_FW_CFG:
            {
                hw_config_start();
            }
            break;

        case BT_VND_OP_SCO_CFG:
            {
#if (SCO_CFG_INCLUDED == TRUE)
                hw_sco_config();
#else
                retval = -1;
#endif
            }
            break;

        case BT_VND_OP_USERIAL_OPEN:
            {
                int (*fd_array)[] = (int (*)[]) param;
                int fd, idx;
                fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
                if (fd != -1)
                {
                    for (idx=0; idx < CH_MAX; idx++)
                        (*fd_array)[idx] = fd;

                    retval = 1;
                }
                /* retval contains numbers of open fd of HCI channels */
            }
            break;

        case BT_VND_OP_USERIAL_CLOSE:
            {
                userial_vendor_close();
            }
            break;

        case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
            {
                uint32_t *timeout_ms = (uint32_t *) param;
                *timeout_ms = hw_lpm_get_idle_timeout();
            }
            break;

        case BT_VND_OP_LPM_SET_MODE:
            {
                uint8_t *mode = (uint8_t *) param;
                retval = hw_lpm_enable(*mode);
            }
            break;

        case BT_VND_OP_LPM_WAKE_SET_STATE:
            {
                uint8_t *state = (uint8_t *) param;
                uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \
                                        TRUE : FALSE;

                hw_lpm_set_wake_state(wake_assert);
            }
            break;

        case BT_VND_OP_EPILOG:
            {
#if (HW_END_WITH_HCI_RESET == FALSE)
                if (bt_vendor_cbacks)
                {
                    bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
                }
#else
                hw_epilog_process();
#endif
            }
            break;
    }

    return retval;
}