/*******************************************************************************
**
** 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;
}
Ejemplo n.º 2
0
/*******************************************************************************
**
** Function         hw_config_cback
**
** Description      Callback function for controller configuration
**
** Returns          None
**
*******************************************************************************/
void hw_config_cback(void *p_mem)
{
    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
    char        *p_name, *p_tmp;
    uint8_t     *p, status;
    uint16_t    opcode;
    HC_BT_HDR  *p_buf=NULL;
    uint8_t     is_proceeding = FALSE;
    int         i;
#if (USE_CONTROLLER_BDADDR == TRUE)
    const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
#endif

    status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE);
    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
    STREAM_TO_UINT16(opcode,p);

    /* Ask a new buffer big enough to hold any HCI commands sent in here */
    if ((status == 0) && bt_vendor_cbacks)
        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
                                                       HCI_CMD_MAX_LEN);

	ALOGI("[Atmel %s] rcvd cb with state: %d!!,status:%d,op_code:%x",__func__, hw_cfg_cb.state,status,opcode);
	if (p_buf != NULL)
	{
		p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
		p_buf->offset = 0;
		p_buf->len = 0;
		p_buf->layer_specific = 0;

        p = (uint8_t *) (p_buf + 1);

        switch (hw_cfg_cb.state)
        {
            case HW_CFG_SET_UART_BAUD_1:
                /* update baud rate of host's UART port */
                ALOGI("bt vendor lib: set UART baud %i", UART_TARGET_BAUD_RATE);
                userial_vendor_set_baud( \
                    line_speed_to_userial_baud(UART_TARGET_BAUD_RATE) \
                );

                /* read local name */
                UINT16_TO_STREAM(p, HCI_READ_LOCAL_NAME);
                *p = 0; /* parameter length */

                p_buf->len = HCI_CMD_PREAMBLE_SIZE;
                hw_cfg_cb.state = HW_CFG_READ_LOCAL_NAME;

                is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_READ_LOCAL_NAME, \
                                                    p_buf, hw_config_cback);
                break;

            case HW_CFG_READ_LOCAL_NAME:
                p_tmp = p_name = (char *) (p_evt_buf + 1) + \
                         HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING;

                for (i=0; (i < LOCAL_NAME_BUFFER_LEN)||(*(p_name+i) != 0); i++)
                    *(p_name+i) = toupper(*(p_name+i));

                if ((p_name = strstr(p_name, "BCM")) != NULL)
                {
                    strncpy(hw_cfg_cb.local_chip_name, p_name, \
                            LOCAL_NAME_BUFFER_LEN-1);
                }
                else
                {
                    strncpy(hw_cfg_cb.local_chip_name, "UNKNOWN", \
                            LOCAL_NAME_BUFFER_LEN-1);
                    p_name = p_tmp;
                }

                hw_cfg_cb.local_chip_name[LOCAL_NAME_BUFFER_LEN-1] = 0;

                BTHWDBG("Chipset %s", hw_cfg_cb.local_chip_name);

                if ((status = hw_config_findpatch(p_name)) == TRUE)
                {
                    if ((hw_cfg_cb.fw_fd = open(p_name, O_RDONLY)) == -1)
                    {
                        ALOGE("vendor lib preload failed to open [%s]", p_name);
                    }
                    else
                    {
                    #if 0
                        /* vsc_download_minidriver */
                        UINT16_TO_STREAM(p, HCI_VSC_DOWNLOAD_MINIDRV);
                        *p = 0; /* parameter length */

                        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
                        hw_cfg_cb.state = HW_CFG_DL_MINIDRIVER;

                        is_proceeding = bt_vendor_cbacks->xmit_cb( \
                                            HCI_VSC_DOWNLOAD_MINIDRV, p_buf, \
                                            hw_config_cback);
					#endif	
                    }
                }
                else
                {
                    ALOGE( \
                    "vendor lib preload failed to locate firmware patch file" \
                    );
                }

                if (is_proceeding == FALSE)
                {
                    //is_proceeding = hw_config_set_bdaddr(p_buf);
                }
                break;

            case HW_CFG_DL_MINIDRIVER:
                /* give time for placing firmware in download mode */
                ms_delay(50);
                hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
                /* fall through intentionally */
            case HW_CFG_DL_FW_PATCH:
                p_buf->len = read(hw_cfg_cb.fw_fd, p, HCI_CMD_PREAMBLE_SIZE);
                if (p_buf->len > 0)
                {
                #if 0
                    if ((p_buf->len < HCI_CMD_PREAMBLE_SIZE) || \
                        (opcode == HCI_VSC_LAUNCH_RAM))
                    {
                        ALOGW("firmware patch file might be altered!");
                    }
                    else
                    {
                        p_buf->len += read(hw_cfg_cb.fw_fd, \
                                           p+HCI_CMD_PREAMBLE_SIZE,\
                                           *(p+HCD_REC_PAYLOAD_LEN_BYTE));
                        STREAM_TO_UINT16(opcode,p);
                        is_proceeding = bt_vendor_cbacks->xmit_cb(opcode, \
                                                p_buf, hw_config_cback);
                        break;
                    }
				#endif
                }

                close(hw_cfg_cb.fw_fd);
                hw_cfg_cb.fw_fd = -1;

                /* Normally the firmware patch configuration file
                 * sets the new starting baud rate at 115200.
                 * So, we need update host's baud rate accordingly.
                 */
                ALOGI("bt vendor lib: set UART baud 115200");
                userial_vendor_set_baud(USERIAL_BAUD_115200);

                /* Next, we would like to boost baud rate up again
                 * to desired working speed.
                 */
                hw_cfg_cb.f_set_baud_2 = TRUE;

                /* Check if we need to pause a few hundred milliseconds
                 * before sending down any HCI command.
                 */
                ms_delay(look_up_fw_settlement_delay());

                /* fall through intentionally */
            case HW_CFG_START:
                if (UART_TARGET_BAUD_RATE > 3000000)
                {
                #if 1
                    /* set UART clock to 48MHz */
                    UINT16_TO_STREAM(p, HCI_VSC_WRITE_UART_CLOCK_SETTING);
                    *p++ = 1; /* parameter length */
                    *p = 1; /* (1,"UART CLOCK 48 MHz")(2,"UART CLOCK 24 MHz") */

                    p_buf->len = HCI_CMD_PREAMBLE_SIZE + 1;
                    hw_cfg_cb.state = HW_CFG_SET_UART_CLOCK;

                    is_proceeding = bt_vendor_cbacks->xmit_cb( \
                                        HCI_VSC_WRITE_UART_CLOCK_SETTING, \
                                        p_buf, hw_config_cback);
                    break;
				#endif
                }
                /* fall through intentionally */
            case HW_CFG_SET_UART_CLOCK:
                /* set controller's UART baud rate to 3M */
                UINT16_TO_STREAM(p, HCI_VSC_UPDATE_BAUDRATE);
                *p++ = UPDATE_BAUDRATE_CMD_PARAM_SIZE; /* parameter length */
                *p++ = 0; /* encoded baud rate */
                *p++ = 0; /* use encoded form */
                UINT32_TO_STREAM(p, UART_TARGET_BAUD_RATE);

                p_buf->len = HCI_CMD_PREAMBLE_SIZE + \
                             UPDATE_BAUDRATE_CMD_PARAM_SIZE;
                hw_cfg_cb.state = (hw_cfg_cb.f_set_baud_2) ? \
                            HW_CFG_SET_UART_BAUD_2 : HW_CFG_SET_UART_BAUD_1;

                is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_UPDATE_BAUDRATE, \
                                                    p_buf, hw_config_cback);
                break;

            case HW_CFG_SET_UART_BAUD_2:
                /* update baud rate of host's UART port */
                ALOGI("bt vendor lib: set UART baud %i", UART_TARGET_BAUD_RATE);
                userial_vendor_set_baud( \
                    line_speed_to_userial_baud(UART_TARGET_BAUD_RATE) \
                );

#if (USE_CONTROLLER_BDADDR == TRUE)
                if ((is_proceeding = hw_config_read_bdaddr(p_buf)) == TRUE)
                    break;
#else
               // if ((is_proceeding = hw_config_set_bdaddr(p_buf)) == TRUE)
                //    break;
#endif
                /* fall through intentionally */
            case HW_CFG_SET_BD_ADDR:
                ALOGI("vendor lib fwcfg completed");
                bt_vendor_cbacks->dealloc(p_buf);
                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);

                hw_cfg_cb.state = 0;

                if (hw_cfg_cb.fw_fd != -1)
                {
                    close(hw_cfg_cb.fw_fd);
                    hw_cfg_cb.fw_fd = -1;
                }

                is_proceeding = TRUE;
                break;

#if (USE_CONTROLLER_BDADDR == TRUE)
            case HW_CFG_READ_BD_ADDR:
                p_tmp = (char *) (p_evt_buf + 1) + \
                         HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY;

                if (memcmp(p_tmp, null_bdaddr, BD_ADDR_LEN) == 0)
                {
                    // Controller does not have a valid OTP BDADDR!
                    // Set the BTIF initial BDADDR instead.
                   // if ((is_proceeding = hw_config_set_bdaddr(p_buf)) == TRUE)
                   //     break;
                }
                else
                {
                    ALOGI("Controller OTP bdaddr %02X:%02X:%02X:%02X:%02X:%02X",
                        *(p_tmp+5), *(p_tmp+4), *(p_tmp+3),
                        *(p_tmp+2), *(p_tmp+1), *p_tmp);
                }

                ALOGI("vendor lib fwcfg completed");
                bt_vendor_cbacks->dealloc(p_buf);
                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);

				hw_cfg_cb.state = 0;

                if (hw_cfg_cb.fw_fd != -1)
                {
                    close(hw_cfg_cb.fw_fd);
                    hw_cfg_cb.fw_fd = -1;
                }

                is_proceeding = TRUE;
                break;
#endif // (USE_CONTROLLER_BDADDR == TRUE)
        } // switch(hw_cfg_cb.state)
    } // if (p_buf != NULL)

    /* Free the RX event buffer */
    if (bt_vendor_cbacks)
        bt_vendor_cbacks->dealloc(p_evt_buf);

    if (is_proceeding == FALSE)
    {
        ALOGE("vendor lib fwcfg aborted!!!");
        if (bt_vendor_cbacks)
        {
            if (p_buf != NULL)
                bt_vendor_cbacks->dealloc(p_buf);

            bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
        }

        if (hw_cfg_cb.fw_fd != -1)
        {
            close(hw_cfg_cb.fw_fd);
            hw_cfg_cb.fw_fd = -1;
        }

        hw_cfg_cb.state = 0;
    }
}