Beispiel #1
0
void usbc_core_notify_func_wk_ability(kal_uint8 class_device_id, kal_bool ability)
{
    usbc_core_t    *pUsbCore = usbc_core_get_instance();
    kal_bool isCapableWk = KAL_FALSE;

    // check the capability of the class device
    if ( NULL != pUsbCore->class_device[class_device_id].query_func_wk_status)
    {
        isCapableWk = ((pUsbCore->class_device[class_device_id].query_func_wk_status(class_device_id) & (kal_uint8)0x01) == 0x01)? KAL_TRUE:KAL_FALSE;
    }
    if( ability && !isCapableWk )
    {
        usbc_trace_error(USBCORE_NOTIFY_WK_ABILITY_INVALID, pUsbCore->class_device[class_device_id].class_type);
        ASSERT(0);
        return;
    }

    if ( USBC_CORE_CLASS_DEVICE_STATE_REGISTERED == pUsbCore->class_device[class_device_id].state &&
         NULL != pUsbCore->class_device[class_device_id].notify_func_wk_ability )
    {
        usbc_trace_info(USBCORE_NOTIFY_WK_ABILITY_START, pUsbCore->class_device[class_device_id].class_type);
        pUsbCore->class_device[class_device_id].notify_func_wk_ability(class_device_id, ability);
        usbc_trace_info(USBCORE_NOTIFY_WK_ABILITY_END, pUsbCore->class_device[class_device_id].class_type);
    }
}
Beispiel #2
0
void usbc_core_notify_state_resume()
{
    kal_bool remote_wakeup_enabled = (usbc_core_get_function_remote_wk_list()==0)? KAL_FALSE:KAL_TRUE;

    if( USBC_IS_IN_EXCEPTION_MODE() )
    {
        usbc_core_indicate_state(USBC_USB_STATE_RESUME);
        return;
    }


    // nofity USBIDLE that it does not have to gate the clock of USB IP
    usbc_trace_info(USBCORE_DEV_SUSPEND_CLOCK, 0, 0);
    usb_idle_set_clockGating(KAL_FALSE);

    // Notify USB resume event to USB classes
    usbc_core_indicate_state(USBC_USB_STATE_RESUME);

    // Update function pointer for set GPDs to hardware normally
    usbc_trace_info(USBCORE_UPDATE_API_BUFF_GPD, 0);
    usbc_normal_hif_factory();

    // Set GPDs that are buffered in DRAM to hardware
    usbc_normal_hif_restore_gpd_pwrsave();

    // Set USBCORE task to wait for both indication events and tick events
    usbc_trace_info(USBCORE_SUSPEND_START_POLL);
    usbc_core_get_instance()->hmu_indication = HIF_DRV_EG_HIF_TICK_EVENT | HIF_DRV_EG_USBC_IND_EVENT;

    // Ask USBIDLE to notify L4 to turn RF power on or go back to normal operation state
    usbc_trace_info(USBCORE_DEV_SUSPEND_L4, 0, 0, 0, (remote_wakeup_enabled? 1:0));
    usb_idle_set_l4_power_saving(KAL_FALSE);
    usb_idle_event_notify_to_l4(KAL_FALSE, remote_wakeup_enabled);
}
Beispiel #3
0
void usbc_core_notify_state_reset()
{
    kal_bool remote_wakeup_enabled = (usbc_core_get_function_remote_wk_list()==0)? KAL_FALSE:KAL_TRUE;

    if( USBC_IS_IN_EXCEPTION_MODE() )
    {
        usbc_core_indicate_state(USBC_USB_STATE_RESET);
        usbc_core_clear_status();
        return;
    }


    // nofity USBIDLE that it does not have to gate the clock of USB IP
    usbc_trace_info(USBCORE_DEV_SUSPEND_CLOCK, 0, 0);
    usb_idle_set_clockGating(KAL_FALSE);

    // Update function pointer for set GPDs to hardware normally
    usbc_trace_info(USBCORE_UPDATE_API_BUFF_GPD, 0);
    usbc_normal_hif_factory();

    // Notify USB reset event to USB classes and clear USB status
    usbc_core_indicate_state(USBC_USB_STATE_RESET);
    usbc_core_clear_status();

    // Ask USBIDLE to notify L4 to turn RF power on or go back to normal operation state
    usbc_trace_info(USBCORE_DEV_SUSPEND_L4, 0, 0, 0, (remote_wakeup_enabled? 1:0));
    usb_idle_set_l4_power_saving(KAL_FALSE);
    usb_idle_event_notify_to_l4(KAL_FALSE, remote_wakeup_enabled);
}
Beispiel #4
0
/*------------------------------------------------------------------------------
 * Private implementation.
 *----------------------------------------------------------------------------*/
static void usbc_core_indicate_state(usbc_usb_state_e state)
{
    usbc_core_t    *pUsbCore = usbc_core_get_instance();
    kal_uint8       idx;

    pUsbCore->state = state;

    for (idx = 0; idx < pUsbCore->total_class_devices; idx++) {
        if ( USBC_CORE_CLASS_DEVICE_STATE_REGISTERED == pUsbCore->class_device[idx].state &&
             NULL != pUsbCore->class_device[idx].notify_usb_state )
        {
            if ( (state == USBC_USB_STATE_SUSPENDING || state == USBC_USB_STATE_SUSPENDED) &&
                 pUsbCore->class_device[idx].is_func_suspend )
            {
                // do not suspend the class device again if it has been in function suspend state
            }
            else if ( state == USBC_USB_STATE_RESUME && pUsbCore->class_device[idx].is_func_suspend )
            {
                // do not resume the class device which was function suspended while device resuming
                // the class device will be resumed later while function resuming
            }
            else
            {
                usbc_trace_info(USBCORE_NOTIFY_CLASS_START, pUsbCore->class_device[idx].class_type, state);
                pUsbCore->class_device[idx].notify_usb_state(idx,state);
                usbc_trace_info(USBCORE_NOTIFY_CLASS_END, pUsbCore->class_device[idx].class_type, state);
            }
        } 
    }
}
void usbc_reinit_class(void)
{
    kal_uint32   idx;
    usbc_class_reinit_func_t  class_reinit;

    for (idx = 0; idx < USB_CLASS_NUM; idx++) {
        class_reinit = _get_class_reinit_func(idx);
        if (class_reinit) {
            usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_REINIT_CLASS_START, idx);
            class_reinit(KAL_FALSE);
            usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_REINIT_CLASS_END, idx);
        } else {
            EXT_ASSERT(KAL_FALSE, 2, 0, 0);
        }
    }
}
Beispiel #6
0
void usbc_core_notify_function_state_suspending(kal_uint8 class_device_id)
{
    kal_uint8 func_suspend_list;
    kal_uint8 func_wk_list = usbc_core_get_function_remote_wk_list();
    usbc_core_t *pUsbCore = usbc_core_get_instance();
    usbcore_usbidle_l4_power_saving_req_struct *rsp_msg_p;

    // Notify the specific function of USB suspended
    if ( !pUsbCore->class_device[class_device_id].is_func_suspend )
    {
        usbc_core_indicate_function_state(class_device_id, USBC_USB_STATE_SUSPENDING);
        usbc_core_indicate_function_state(class_device_id, USBC_USB_STATE_SUSPENDED);
        pUsbCore->class_device[class_device_id].is_func_suspend = KAL_TRUE;
    }

    // If all functions of the device are suspended, we notify L4 to do power saving
    func_suspend_list = usbc_core_get_function_suspend_list();
    if( !USBC_IS_IN_EXCEPTION_MODE() &&
        func_suspend_list == ((0x01 << pUsbCore->total_class_devices)-1) )
    {
        rsp_msg_p = (usbcore_usbidle_l4_power_saving_req_struct*)construct_local_para(sizeof(usbcore_usbidle_l4_power_saving_req_struct), TD_RESET);
        ASSERT(rsp_msg_p);
        rsp_msg_p->notify_suspend = KAL_TRUE;
        rsp_msg_p->notify_suspend_with_remote_wk = (func_wk_list==0)? KAL_FALSE:KAL_TRUE;
        usbc_trace_info(USBCORE_DEV_SUSPEND_L4, 1, 1, 1, (rsp_msg_p->notify_suspend_with_remote_wk? 0:1));
        usb_idle_set_l4_power_saving(KAL_TRUE);
        msg_send6(MOD_USBCORE,  // src module
                  MOD_USBIDLE,  // dst module
                  0,       // sap id
                  MSG_ID_USBCORE_IDLE_NOTIFY_TO_L4,
                  (local_para_struct*)rsp_msg_p,
                  0); //msg id
    }
}
void usbc_set_wk_notify_timer(kal_uint8 class_device_id)
{
    eventid         eid;
    kal_uint8       nInterface;
    usbc_core_t* pUsbCore = usbc_core_get_instance();
    /*
     * To prevent race condition of event cancelling and set,
     * there shall be only one such event for simplicity.
     */
    ASSERT(NULL != pUsbCore->usbc_es_wk_notify_g);

    usbc_trace_info(USBCORE_REMOTE_WK_SET_NOTIFY_TIMER, class_device_id);

    USBC_CLASS_REMOTE_WK_LOCK(pUsbCore->usbc_class_renotify_mutex);

    // usb a bitmap to maintain the list of function wakeup notification
    pUsbCore->func_notify_list[class_device_id] = KAL_TRUE;

    // get the firtst interface ot the function
    nInterface = usbc_class_device_get_1st_interface(class_device_id);
    // send function remote wakeup notification via HIF driver
    usbc_normal_hif_ss_wk_notify(nInterface); 

    if (NULL == pUsbCore->wk_eventid)
    {
        eid = evshed_set_event(
                pUsbCore->usbc_es_wk_notify_g,
                usbc_wk_notify_timeout,     // timeout handler
                NULL, /* event_hf_param */
                USBC_WK_NOTIFY_CHECK_TICKS); /* elapse_time */
        ASSERT(eid);
    }

    USBC_CLASS_REMOTE_WK_UNLOCK(pUsbCore->usbc_class_renotify_mutex);
}
Beispiel #8
0
void usbc_core_notify_state_suspending()
{
    kal_uint8 func_list;
    usbcore_usbidle_l4_power_saving_req_struct *rsp_msg_p;

    // notify USBCLASS of USB suspended
    usbc_core_indicate_state(USBC_USB_STATE_SUSPENDING);
    usbc_core_indicate_state(USBC_USB_STATE_SUSPENDED);

    if( USBC_IS_IN_EXCEPTION_MODE() )
    {
        return;
    }	    

    // Updatea function pointer for setting GPDs in DRAM buffer
    usbc_trace_info(USBCORE_UPDATE_API_BUFF_GPD, 1);
    usbc_suspended_hif_factory();

    // Notify USBIDLE task to gate USB clock
    usbc_trace_info(USBCORE_DEV_SUSPEND_CLOCK, 1, 1);
    usb_idle_set_clockGating(KAL_TRUE);         // notify USBIDLE that it has to gate the clock of USB IP
    msg_send4(MOD_USBCORE,  // src module
              MOD_USBIDLE,  // dst module
              0,       // sap id
              MSG_ID_USBCORE_SUSPEND_TO_IDLE); //msg id

    // Ask USBIDLE to notify L4 to turn RF power off or go to fast dormancy
    func_list = usbc_core_get_function_remote_wk_list();
    rsp_msg_p = (usbcore_usbidle_l4_power_saving_req_struct*)construct_local_para(sizeof(usbcore_usbidle_l4_power_saving_req_struct), TD_RESET);
    ASSERT(rsp_msg_p);
    rsp_msg_p->notify_suspend = KAL_TRUE;
    rsp_msg_p->notify_suspend_with_remote_wk = (func_list==0)? KAL_FALSE:KAL_TRUE;
    usbc_trace_info(USBCORE_DEV_SUSPEND_L4, 1, 1, 1, (rsp_msg_p->notify_suspend_with_remote_wk? 1:0));
    usb_idle_set_l4_power_saving(KAL_TRUE);
    msg_send6(MOD_USBCORE,  // src module
              MOD_USBIDLE,  // dst module
              0,       // sap id
              MSG_ID_USBCORE_IDLE_NOTIFY_TO_L4,
              (local_para_struct*)rsp_msg_p,
              0); //msg id
 
    // Set USBCORE task to wait for indication events only
    usbc_trace_info(USBCORE_SUSPEND_STOP_POLL);
    usbc_core_get_instance()->hmu_indication = HIF_DRV_EG_USBC_IND_EVENT;   // Set USBCORE task to wait for indication events only
}
void usbc_mode_switch(usb_mode_e mode){
	kal_uint32   idx;
	usbc_core_t* usbc_inst = usbc_core_get_instance();
	usbc_class_reinit_func_t  class_reinit;
	usbc_ind_t      ind_to_enqueue;    // Do mode switch immediately if it is not in HISR, or enqueue a mode switch event for USBCORE task
	if (!kal_if_hisr()) {
#if 1
		if (mode == USB_MODE_MSD_OSDRTY){
		/* wait 3 second for OSD known issue */
			kal_sleep_task(600);
		}
#endif
		/* 1. set disconnect */
		hifusb_set_disconnect();
        usbc_empty_ind_queue();

		/* 2. Set switch mode */
		usbc_inst->is_mode_switch = KAL_TRUE;
		usbc_inst->mode = mode;

		/* 3. Send re-init callback to all usb class */
		_SET_NODE_VALUE(0);
		usbc_stack_checkin(USB_CLASS_NUM, NULL);
		for (idx = 0; idx < USB_CLASS_NUM; idx++) {
			class_reinit = _get_class_reinit_func(idx);
			_SET_NODE_REG_TABLE(idx, NULL);
			if (class_reinit) {
				usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_REINIT_CLASS_START, idx);
				class_reinit(KAL_TRUE);
				usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_REINIT_CLASS_END, idx);
			} else {
					EXT_ASSERT(KAL_FALSE, 2, 0, 0);
			}
		}
	} else {
		ind_to_enqueue.type = USBC_IND_MODE_SWITCH;
		ind_to_enqueue.ext = 0;
		ind_to_enqueue.data = (kal_uint8)mode;
		usbc_enqueue_ind(&ind_to_enqueue);
		hmu_hifeg_set(HIF_DRV_EG_USBC_IND_EVENT);
	}
}
Beispiel #10
0
static void usbc_core_handle_set_address()
{
    usbc_core_t* pUsbCore = usbc_core_get_instance();
    kal_uint16 wValue = pUsbCore->setup_packet.wValue;

    usbc_core_printf("=========>usbcore_handle_set_address\r\n");
    usbc_trace_info(USBCORE_SET_ADDRESS, (wValue & 0x7f));

    usbc_core_set_usb_address(wValue & 0x7f);
    usbc_core_set_control_request(NULL, 0, USBC_CONTROL_REQUEST_TYPE_RECEIVE);
}
Beispiel #11
0
/*!
 *  @brief This function is used to notify function suspend or function resume to a specific class device
 */
static void usbc_core_indicate_function_state(kal_uint8 class_device_id, usbc_usb_state_e state)
{
    usbc_core_t *pUsbCore = usbc_core_get_instance();

    if ( state != USBC_USB_STATE_SUSPENDING &&
         state != USBC_USB_STATE_SUSPENDED &&
         state != USBC_USB_STATE_RESUME )
    {
        ASSERT(0);
        return;
    }

    if ( USBC_CORE_CLASS_DEVICE_STATE_REGISTERED == pUsbCore->class_device[class_device_id].state &&
         NULL != pUsbCore->class_device[class_device_id].notify_usb_state )
    {
        usbc_trace_info(USBCORE_NOTIFY_CLASS_START, pUsbCore->class_device[class_device_id].class_type, state);
        pUsbCore->class_device[class_device_id].notify_usb_state(class_device_id, state);
        usbc_trace_info(USBCORE_NOTIFY_CLASS_END, pUsbCore->class_device[class_device_id].class_type, state);

    }
}
Beispiel #12
0
void usbc_core_notify_function_state_resume(kal_uint8 class_device_id)
{
    kal_uint8 func_suspend_list = usbc_core_get_function_suspend_list();
    kal_bool remote_wakeup_enabled = (usbc_core_get_function_remote_wk_list()==0)? KAL_FALSE:KAL_TRUE;

    usbc_core_t *pUsbCore = usbc_core_get_instance();

    // Notify the specific function of USB resuming
    if ( pUsbCore->class_device[class_device_id].is_func_suspend )
    {
        usbc_core_indicate_function_state(class_device_id, USBC_USB_STATE_RESUME);
        pUsbCore->class_device[class_device_id].is_func_suspend = KAL_FALSE;
    }

    // Notify L4 to go back to normal operation states if function resumes from the status that all functions are suspended before
    if( !USBC_IS_IN_EXCEPTION_MODE() &&
        func_suspend_list == ((0x01 << pUsbCore->total_class_devices)-1) )
    {
        usbc_trace_info(USBCORE_DEV_SUSPEND_L4, 0, 0, 0, (remote_wakeup_enabled? 0:1));
        usb_idle_set_l4_power_saving(KAL_FALSE);
        usb_idle_event_notify_to_l4(KAL_FALSE, remote_wakeup_enabled);
    }
}
Beispiel #13
0
static void usbc_core_handle_set_feature()
{
    usbc_core_t* pUsbCore = usbc_core_get_instance();
    usbc_control_request_type_e type = USBC_CONTROL_REQUEST_TYPE_STALL;
    kal_uint8 bRecip = pUsbCore->setup_packet.bmRequestType & USBC_REQUEST_RECIP_MASK;
    kal_uint16 wIndex = pUsbCore->setup_packet.wIndex;
    kal_uint16 wValue = pUsbCore->setup_packet.wValue;
    kal_bool is_tx = KAL_TRUE;

    usbc_core_printf("=========>usbcore_handle_set_feature\r\n");
    usbc_trace_info(USBCORE_SET_FEATURE, bRecip, wIndex, wValue);

    if ( bRecip == USBC_REQUEST_RECIP_DEVICE )
    {
        usbc_ind_t          ind_to_enqueue;
        usbc_func_state_e   state;
        kal_uint8 i;

        if ( pUsbCore->speed == USBC_USB_SPEED_USB30 )
        {
            if ( pUsbCore->state <= USBC_USB_STATE_ATTACHING )
            {
                type = USBC_CONTROL_REQUEST_TYPE_STALL;
            } else
            if ( wValue == USBC_FEATURE_U1_ENABLE )
            {
                pUsbCore->is_device_u1_enable = KAL_TRUE;
                usbc_core_set_ss_dev_init_u1_en(KAL_TRUE);
                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            } else
            if ( wValue == USBC_FEATURE_U2_ENABLE )
            {
                pUsbCore->is_device_u2_enable = KAL_TRUE;
                usbc_core_set_ss_dev_init_u2_en(KAL_TRUE);
                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            } else
            if ( wValue == USBC_FEATURE_LTM_ENABLE )
            {
                pUsbCore->is_device_ltm_enable = KAL_TRUE;
                // TODO: set LTM enabled if support
                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            }
#if _USB30_DEVICE_REMOTE_WK_SUPPORT_
            else if ( wValue == USBC_FEATURE_DEVICE_REMOTE_WAKEUP )
            {
                // enable function remote wakeup for capable functions in enabling device remote wakeup
                state = USBC_FUNC_WK_ENABLE;
                for( i=0; i<pUsbCore->total_class_devices; i++)
                {
                    if ( NULL != pUsbCore->class_device[i].query_func_wk_status &&
                         pUsbCore->class_device[i].query_func_wk_status(i) & ((kal_uint8)0x01) )
                    {
                        ind_to_enqueue.type = USBC_IND_FUNC_EVENT;
                        ind_to_enqueue.ext = i;
                        ind_to_enqueue.data = (kal_uint8)state;
                        usbc_enqueue_ind(&ind_to_enqueue);
                    }
                }
                hmu_hifeg_set(HIF_DRV_EG_USBC_IND_EVENT);

                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            }
#endif
            else
            {
                 type = USBC_CONTROL_REQUEST_TYPE_STALL;
            }
        }
        else
        {
            if ( wValue == USBC_FEATURE_DEVICE_REMOTE_WAKEUP )
            {
                // enable function remote wakeup for capable functions in enabling device remote wakeup
                state = USBC_FUNC_WK_ENABLE;
                for( i=0; i<pUsbCore->total_class_devices; i++)
                {
                    if ( NULL != pUsbCore->class_device[i].query_func_wk_status &&
                         pUsbCore->class_device[i].query_func_wk_status(i) & ((kal_uint8)0x01) )
                    {
                        ind_to_enqueue.type = USBC_IND_FUNC_EVENT;
                        ind_to_enqueue.ext = i;
                        ind_to_enqueue.data = (kal_uint8)state;
                        usbc_enqueue_ind(&ind_to_enqueue);
                    }
                }
                hmu_hifeg_set(HIF_DRV_EG_USBC_IND_EVENT);

                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            } else
            if ( wValue == USBC_FEATURE_TEST_MODE )
            {
                usbc_core_set_usb_testmode((hifusb_test_mode_e)(wIndex >> 8));
                type = USBC_CONTROL_REQUEST_TYPE_RECEIVE;
            }
            else
            {
Beispiel #14
0
static void usbc_core_handle_get_status()
{
    usbc_core_t* pUsbCore = usbc_core_get_instance();
    usbc_control_request_type_e type = USBC_CONTROL_REQUEST_TYPE_STALL;
    kal_uint8 bRecip = pUsbCore->setup_packet.bmRequestType & USBC_REQUEST_RECIP_MASK;
    //kal_uint16 wIndex = pUsbCore->setup_packet.wIndex;
    kal_uint8* pBuffer = pUsbCore->control_request_buffer;
    kal_uint32 length = 0;

    usbc_core_printf("=========>usbcore_handle_get_status\r\n");
    usbc_trace_info(USBCORE_GET_STATUS, bRecip);

    if ( bRecip == USBC_REQUEST_RECIP_DEVICE )
    {
        kal_uint8 i;

        /* D0: Self Powered, D1: Remote Wakeup */
        pBuffer[0] = 0;     //Bus Power
        pBuffer[1] = 0;     //No Remote Wakeup
        length = 2;
        type = USBC_CONTROL_REQUEST_TYPE_SEND;

        // report remote wakeup status in USB 1.1 and USB 2.0 (0 in USB 3.0)
        if( pUsbCore->speed != USBC_USB_SPEED_USB30 )
        {
            for( i=0; i<pUsbCore->total_class_devices; i++)
            {
                if ( NULL != pUsbCore->class_device[i].query_func_wk_status &&
                     pUsbCore->class_device[i].query_func_wk_status(i) & 0x0002 )
                {
                    pBuffer[0] |= ((kal_uint8)0x01 << 1);
                    break;
                }
            }
        }
		else
		{
            // USB 3.0 U1 enable status (0 in USB 2.0)
            if ( pUsbCore->is_device_u1_enable )
            {
                pBuffer[0] |= ((kal_uint8)0x01 << 2);
            }

            // USB 3.0 U2 enable status ( 0 in USB 3.0)
            if( pUsbCore->is_device_u2_enable )
            {
                pBuffer[0] |= ((kal_uint8)0x01 << 3);
            }

            // USB 3.0 LTM enable status ( 0 in USB 3.0)
            if( pUsbCore->is_device_ltm_enable )
            {
                pBuffer[0] |= ((kal_uint8)0x01 << 4);
            }
		}

    } else
    if ( bRecip == USBC_REQUEST_RECIP_INTERFACE )
    {
        kal_uint8 nInterface = (kal_uint8)pUsbCore->setup_packet.wIndex;
        kal_uint8 class_device_id = pUsbCore->class_interface[nInterface].class_device_id;

        /* return two bytes of 0x00, 0x00.
           Both bytes are reserved for future use
         */
        pBuffer[0] = 0;
        pBuffer[1] = 0;
        length = 2;
        type = USBC_CONTROL_REQUEST_TYPE_SEND;

        if ( pUsbCore->speed == USBC_USB_SPEED_USB30 &&
             usbc_core_is_1st_interface(nInterface)  &&
             NULL !=  pUsbCore->class_device[class_device_id].query_func_wk_status )
        {
            /* if the requested interface is the first one of a function,
               report the function remote wakeup capability and state
             */
            pBuffer[0] = pUsbCore->class_device[class_device_id].query_func_wk_status(class_device_id) & ((kal_uint8)0xFF);
        }

    } else
    if ( bRecip == USBC_REQUEST_RECIP_ENDPOINT )
    {
        /* D0: HALT, D1: Reserve */
        kal_uint8 nEnd = pUsbCore->setup_packet.wIndex & USBC_EP_ADDR_NUM_MASK; /* TODO: It's error-prone to use en_no instead of endpoint address. */
        usbc_core_queue_t* pQueue = NULL;
        kal_uint8 i = 0;

        if ( (pUsbCore->setup_packet.wIndex & USBC_EP_ADDR_DIR_IN) )
        {
            for ( i=0; i<MAX_USBCORE_QUEUE_NUM; i++ )
            {
                if ( (pUsbCore->tx_queue[i].ep_no == nEnd) &&
                     (pUsbCore->tx_queue[i].state > USBC_CORE_QUEUE_STATE_INITIATED) )
                {
                    pQueue = &pUsbCore->tx_queue[i];
                    break;
                }
            }
        } else {
            for ( i=0; i<MAX_USBCORE_QUEUE_NUM; i++ )
            {
                if ( (pUsbCore->rx_queue[i].ep_no == nEnd) &&
                     (pUsbCore->rx_queue[i].state > USBC_CORE_QUEUE_STATE_INITIATED) )
                {
                    pQueue = &pUsbCore->rx_queue[i];
                    break;
                }
            }
        }

        /* D0: HALT, D1: Reserve */
        if ( pQueue == NULL )
        {
            length = 0;
            type = USBC_CONTROL_REQUEST_TYPE_STALL;

            if( nEnd == 0)
            {
                pBuffer[0] = 0;
                pBuffer[1] = 0;
                length = 2;
                type = USBC_CONTROL_REQUEST_TYPE_SEND;
            }

        } else {
            switch (pQueue->state)
            {
                case USBC_CORE_QUEUE_STATE_ACTIVE:
                {
                    pBuffer[0] = 0;
                    pBuffer[1] = 0;
                    length = 2;
                    type = USBC_CONTROL_REQUEST_TYPE_SEND;
                    break;
                }
                case USBC_CORE_QUEUE_STATE_STALL:
                {
                    pBuffer[0] = 1;
                    pBuffer[1] = 0;
                    length = 2;
                    type = USBC_CONTROL_REQUEST_TYPE_SEND;
                    break;
                }
                default:
                {
                    ASSERT(0);
                    length = 0;
                    type = USBC_CONTROL_REQUEST_TYPE_STALL;
                    break;
                }
            }
        }
    } else {
        ASSERT(0);
        type = USBC_CONTROL_REQUEST_TYPE_STALL;
    }

    usbc_core_set_control_request(pBuffer, length, type);

}
/*
   usbcore:        usbc_stack_checkin(USB_CLASS_NUM, NULL);
   usbclass:   ex. usbc_stack_checkin(USB_CLASS_ACM1, XXX);
 */
void usbc_stack_checkin(usb_class_type_e class_type, usbc_node_reg_entry_t *reg_table)
{
    usbc_class_init_func_t  class_init;
    kal_uint32              idx_cfg, idx_class;
    kal_uint32              cfg_num;
    usb_cfg_param_t        *cfg_param;
    usbc_device_descriptor_t *dev_desc;
    usbc_device_qualifier_descriptor_t *dev_qual_desc;
    usbc_configuration_descriptor_t  *config_desc_p;
    usbc_core_t            *usbc_inst;

    _CHECKIN_NODE(class_type, reg_table);

    if (_ALL_NODES_CHECKIN())
    {
        usbc_trace_info(USBCORE_ALL_NODE_CHECKIN);

        usbc_inst = usbc_core_get_instance();

        /* 1. hif init */
        usbc_normal_hif_init();

        // Check for META mode
        #if defined(__MTK_TARGET__) && defined(__MULTI_BOOT__) && !defined(__ESL_COSIM_HIF__)
        if( INT_BootMode() == MTK_FACTORY_MODE )
        {
            usbc_inst->is_mode_meta = KAL_TRUE;
            usbc_inst->is_mode_meta_reused = usbc_normal_hif_is_meta_reused();
        }
        else
        #endif
        {
            usbc_inst->is_mode_meta = usbc_inst->is_mode_meta_reused = KAL_FALSE;
        }

        /* 2. Reset usbcore resources/structures */
        usbc_resource_reset();
        usbc_core_clear_register();
        usbc_core_clear_status();

        /*
           3. If Morphing is enabled, use WIN8 mode configuration
              If it is resulted from mode switch, use usbc_inst->mode
        */
        usbc_inst->dev_param = (usb_dev_param_t*)usb_get_custom_func()->get_device_param_func();

        if( !usbc_inst->is_mode_meta )
        {
        #if defined (BTT_STANDALONE_MODE)
            usbc_inst->mode = USB_MODE_BTT_STANDALONE;
        #elif defined(__ESL_COSIM_HIF__)
            usbc_inst->mode = USB_MODE_ESL;
        #else
            if (!usbc_inst->is_mode_switch)
            {
                usbc_inst->morphing_enable = (custom_em_get_usb_cdrom_config() & 0x02)? KAL_TRUE:KAL_FALSE; // check for morphing enable

                if ( usbc_inst->morphing_enable )
                {
                    usbc_inst->mode = usbc_inst->dev_param->usb_mode[USB_OS_WIN8];
                }
                else
                {
                    if( (custom_em_get_usb_cdrom_config() & 0x01) == 0 )
                    {
                        usbc_inst->mode = USB_MODE_MSD_ONLY;
                    }
                    else
                    {
                        usbc_inst->mode = USB_MODE_MT6290_DATACARD;
                    }
                }

            }
        #endif
        }
        else
        {
            // set USB enumeration to USB_MODE_META if it is in meta mode
            usbc_inst->mode = USB_MODE_META;
        }

        cfg_num = usbc_inst->dev_param->mode_param[usbc_inst->mode].cfg_num;

        /* 4. Set device_descriptor */
        dev_desc = (usbc_device_descriptor_t *)usbc_inst->descriptors.device;
        kal_mem_cpy(dev_desc, &usbc_default_device_descriptor, USBC_DEVICE_DESC_SIZE);
        dev_desc->bDeviceClass = usbc_inst->dev_param->mode_param[usbc_inst->mode].device_class;
        dev_desc->bDeviceSubClass = usbc_inst->dev_param->mode_param[usbc_inst->mode].device_sub_class;
        dev_desc->bDeviceProtocol = usbc_inst->dev_param->mode_param[usbc_inst->mode].device_protocol;
        dev_desc->idVendor = usbc_inst->dev_param->vendor_id;
        dev_desc->idProduct = usbc_inst->dev_param->mode_param[usbc_inst->mode].product_id;
        dev_desc->bcdDevice = usbc_inst->dev_param->bcd_device;
        dev_desc->bNumConfigurations = usbc_inst->dev_param->mode_param[usbc_inst->mode].cfg_num;

        dev_qual_desc = &usbc_inst->device_qualifier_descriptor;
        dev_qual_desc->bLength = 0x0A;
        dev_qual_desc->bDescriptorType = USBC_DT_DEVICE_QUALIFIER;
        dev_qual_desc->bcdUSB = dev_desc->bcdUSB;
        dev_qual_desc->bDeviceClass = dev_desc->bDeviceClass;
        dev_qual_desc->bDeviceSubClass = dev_desc->bDeviceSubClass;
        dev_qual_desc->bDeviceProtocol = dev_desc->bDeviceProtocol;
        dev_qual_desc->bMaxPacketSize0 = dev_desc->bMaxPacketSize0;
        dev_qual_desc->bNumConfigurations = dev_desc->bNumConfigurations;

        /* 5. Store device string - language/manufacturere/product/serialnum */
        usbc_get_string_number((void*)usb_language_string);
        dev_desc->iManufacturer = usbc_get_string_number((void*)usbc_inst->dev_param->manufacture_string);
        dev_desc->iProduct = usbc_get_string_number((void*)usbc_inst->dev_param->product_string);
        // Update serial number by reading the IMEI from NVRAM
#ifdef __PRODUCTION_RELEASE__
        dev_desc->iSerialNumber = usbc_core_set_serial_number()? usbc_get_string_number((void*)usbc_inst->dev_param->serial_number):0x00;
#else
/* under construction !*/
#endif

        /* 6. Call init function of each usb class for all configurations */
        for (idx_cfg = 0; idx_cfg < cfg_num; idx_cfg++)
        {
            cfg_param = &usbc_inst->dev_param->mode_param[usbc_inst->mode].cfg_param[idx_cfg];
            for (idx_class = 0; idx_class < cfg_param->class_num; idx_class++)
            {
                class_init = _get_class_init_func(cfg_param->class_type[idx_class]);
                if (class_init) {
                    usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_INIT_CLASS_START, cfg_param->class_type[idx_class]);
                    class_init( idx_class,
                                usbc_inst->mode,
                                idx_cfg,
                                cfg_param->class_ctxt[idx_class],
                                cfg_param->bulk_double_fifo_bitmap[idx_class]);
                    usbc_trace_info(USBCORE_ALL_NODE_CHECKIN_INIT_CLASS_END, cfg_param->class_type[idx_class]);
                } else {
                    EXT_ASSERT(KAL_FALSE, 1, 0, 0);
                }
            }
        }


        if( !usbc_inst->is_mode_meta_reused )
        {
            /* 7. Construct configuration descriptor */
            _usbc_construct_config_descriptor(usbc_inst);

            /* 8. Update descriptors for META (non-reuse COM) */
            if(usbc_inst->is_mode_meta)
            {
                dev_desc->idProduct = 0x7101;
            }

            /* 9. Set configuration and connect to hif */
            usbc_normal_hif_disconnect();
            usbc_core_set_hif_configuration();
            usbc_normal_hif_connect();
        }
        else
        {
            /* 7. Construct configuration descriptor */
            usbc_inst->resource_iad_number[0] = 0;          // Discard IAD if it is in META mode
            _usbc_construct_config_descriptor(usbc_inst);   // construct configuration descriptor

            /* 8. Update descriptors for META */
            dev_desc->iSerialNumber = 0x00;     // no serial number in BootROM/pre-loader's COM
            config_desc_p = (usbc_configuration_descriptor_t*)usbc_inst->descriptors.configuration[0];   // only one configuration in META mode
            config_desc_p->bmAttributes &= 0xdf;   // the remote wakeup is not capable in BootROM/Pre-loader COM
            config_desc_p->bMaxPower = 0xc8;       // the max power of BootROM/Preloader COM's confiuration is 400mA
            usbc_inst->u3ConfMaxPower = (U3_CONF_BMAXPOWER_META / USBC_USB30_POWER_DESC_UINT); // the max power is 400mA in USB 3.0

            /* 9. Enqueue and prepare for fake enumeration */
            usbc_meta_hif_factory();            // set function pointers of USB driver to META state
            usbc_core_set_hif_configuration();
            usbc_normal_hif_meta_attach();
        }

    }
}
kal_bool usbc_class_device_func_remote_wk(kal_uint8 class_device_id)
{

    usbc_core_t* pUsbCore = usbc_core_get_instance();
    kal_bool isDeviceSuspend;
    usbc_ind_t          ind_to_enqueue;
    usbc_func_state_e    state;

    usbc_trace_info(USBCORE_REMOTE_WK_START, class_device_id);

    USBC_NON_EXCEPTION_MODE_CHECK();
    USBC_CLASS_DEVICE_CONTEXT_CHECK();

    /* Check whether the requested function is capable to wakeup the host and remote wakeup is enabled.
       Return KAL_FALSE if the function is not valid to wakeup host
     */
    if ( pUsbCore->class_device[class_device_id].query_func_wk_status(class_device_id) != 0x03 )
    {
        usbc_trace_error(USBCORE_REMOTE_WK_INVALID, class_device_id, pUsbCore->class_device[class_device_id].query_func_wk_status(class_device_id));
        ASSERT(0);
        return KAL_FALSE;
    }

    // check for the remote wakeup once a function at the same time
    USBC_CLASS_REMOTE_WK_LOCK(pUsbCore->usbc_class_remote_wk_mutex);

    // reset the status of function accessing of class device id
    USBC_CLASS_REMOTE_WK_LOCK(pUsbCore->usbc_class_func_access_mutex);
    pUsbCore->is_func_be_accessed[class_device_id] = KAL_FALSE;
    USBC_CLASS_REMOTE_WK_UNLOCK(pUsbCore->usbc_class_func_access_mutex);

    isDeviceSuspend = (pUsbCore->state == USBC_USB_STATE_SUSPENDED)? KAL_TRUE:KAL_FALSE;

    /* If it is resumed from device suspend,
            then send hifusb_remote_wakeup first and wait for the resume callback to know LPM state to U0.
       If it is resumed from function suspend,
            then send notification to resume the suspended function in USB Core context.
     */
    if ( isDeviceSuspend )
    {
        usbc_trace_info(USBCORE_REMOTE_WK_DEVICE, class_device_id);
        usb_idle_set_clockGating(KAL_FALSE);    // nofity USBIDLE that it does not have to gate the clock of USB IP 
        usbc_normal_hif_remote_wakeup();
    }

    //else if ( pUsbCore->class_device[class_device_id].is_func_suspend )
    if ( pUsbCore->class_device[class_device_id].is_func_suspend )
    {
        // block until device resume
        while ( isDeviceSuspend )
        {
            kal_sleep_task(USBC_DEV_RESUME_DURATION_TICK);
            isDeviceSuspend = (pUsbCore->state == USBC_USB_STATE_SUSPENDED)? KAL_TRUE:KAL_FALSE;
            usbc_trace_warn(USBCORE_REMOTE_WK_DEVICE_WAIT, class_device_id);
        }

        usbc_trace_info(USBCORE_REMOTE_WK_FUNC, class_device_id);
        // send callback to notify class device of resuming
        state = USBC_FUNC_STATE_RESUME;
        // Enqueue USB function state which will be handled in USB context later.
        ind_to_enqueue.type = USBC_IND_FUNC_EVENT;
        ind_to_enqueue.ext = class_device_id;
        ind_to_enqueue.data = (kal_uint8)state;
        usbc_enqueue_ind(&ind_to_enqueue);
        // Wake up USBCORE task to process indications.
        hmu_hifeg_set(HIF_DRV_EG_USBC_IND_EVENT);
    }

    // release for the remote wakeup of a function
    USBC_CLASS_REMOTE_WK_UNLOCK(pUsbCore->usbc_class_remote_wk_mutex);

    // call HIF driver API to send function wakeup notification, and resend if needed
    if ( pUsbCore->speed == USBC_USB_SPEED_USB30 )
    {
        usbc_set_wk_notify_timer(class_device_id);
    }

    return KAL_TRUE;
}