Beispiel #1
0
/**
 * Answer To Reset (ATR)
 * \param pAtr    ATR buffer
 * \param pLength Pointer for store the ATR length
 */
void ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
{
    uint32_t i;
    uint32_t j;
    uint32_t y;

    *pLength = 0;

    /* Read ATR TS */
    ISO7816_GetChar(&pAtr[0]);
    /* Read ATR T0 */
    ISO7816_GetChar(&pAtr[1]);
    y = pAtr[1] & 0xF0;
    i = 2;

    /* Read ATR Ti */
    while (y) {

        if (y & 0x10) {  /* TA[i] */
            ISO7816_GetChar(&pAtr[i++]);
        }
        if (y & 0x20) {  /* TB[i] */
            ISO7816_GetChar(&pAtr[i++]);
        }
        if (y & 0x40) {  /* TC[i] */
            ISO7816_GetChar(&pAtr[i++]);
        }
        if (y & 0x80) {  /* TD[i] */
            ISO7816_GetChar(&pAtr[i]);
            y =  pAtr[i++] & 0xF0;
        }
        else {
            y = 0;
        }
    }

    /* Historical Bytes */
    y = pAtr[1] & 0x0F;
    for( j=0; j < y; j++ ) {
        ISO7816_GetChar(&pAtr[i++]);
    }

    TRACE_DEBUG_WP("Length = %d", i);
    TRACE_DEBUG_WP("ATR = ");

    for (j=0; j < i; j++) {
        TRACE_DEBUG_WP("%02x ", pAtr[j]);
    }


    TRACE_DEBUG_WP("\n\r");

    *pLength = i;

}
/**
 * \brief      Initialize a list of OV registers.
 * The list of registers is terminated by the pair of values
 * \param     pTwid TWI interface
 * \param     pReglist Register list to be written
 * \return     0 if no error; otherwise TWID_ERROR_BUSY
 */
uint32_t ov_write_regs8(Twid *pTwid, const struct ov_reg* pReglist)
{
    uint32_t err;
    uint32_t size=0;
    const struct ov_reg *pNext = pReglist;
    volatile uint32_t delay;

    TRACE_DEBUG("ov_write_regs:");
    while (!((pNext->reg == OV_REG_TERM) && (pNext->val == OV_VAL_TERM))) 
    {
        err = ov_write_reg8(pTwid, pNext->reg, pNext->val);

        size++;
        for(delay=0;delay<=10000;delay++); 
        if (err == TWID_ERROR_BUSY)
        {
            TRACE_ERROR("ov_write_regs: TWI ERROR\n\r");
            return err;
        }
        TRACE_DEBUG("(0x%02x,0x%02x) \n\r",  pNext->reg,pNext->val);
        pNext++;
    }
    TRACE_DEBUG_WP("\n\r");
    return 0;
}
Beispiel #3
0
/**
 * Reuse first used/released buffer with new buffer address and size to be used
 * in transfer again. Only valid when frame list is ringed. Can be used for
 * both read & write.
 * \param bEndpoint  Endpoint number.
 * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).
 * \param wNewSize   Size of the data buffer
 */
uint8_t USBD_MblReuse( uint8_t  bEndpoint,
                    uint8_t  *pNewBuffer,
                    uint16_t wNewSize )
{
    Endpoint *pEndpoint = &(endpoints[bEndpoint]);
    MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
    USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);

    TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",
        bEndpoint, pEndpoint->state, pTransfer->circList);

    /* Only for Multi-buffer-circle list */

    if (bEndpoint != 0
        && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM
            || pEndpoint->state == UDP_ENDPOINT_SENDINGM)
        && pTransfer->circList) {
    }
    else {

        return USBD_STATUS_WRONG_STATE;
    }

    /* Check if there is freed buffer */

    if (pTransfer->freedBuffer == pTransfer->currBuffer
        && !pTransfer->allUsed) {

        return USBD_STATUS_LOCKED;
   }

    /* Update transfer information */

    if ((++ pTransfer->freedBuffer) == pTransfer->listSize)
        pTransfer->freedBuffer = 0;
    if (pNewBuffer) {
        pBi->pBuffer = pNewBuffer;
        pBi->size    = wNewSize;
    }
    pBi->buffered    = 0;
    pBi->transferred = 0;
    pBi->remaining   = pBi->size;

    /* At least one buffer is not processed */

    pTransfer->allUsed = 0;
    return USBD_STATUS_SUCCESS;
}
Beispiel #4
0
/**
 * Sends data frames through a USB endpoint. Sets up the transfer descriptor
 * list, writes one or two data payloads (depending on the number of FIFO bank
 * for the endpoint) and then starts the actual transfer. The operation is
 * complete when all the data has been sent.
 *
 * *If the size of the frame is greater than the size of the endpoint
 *  (or twice the size if the endpoint has two FIFO banks), then the buffer
 *  must be kept allocated until the frame is finished*. This means that
 *  it is not possible to declare it on the stack (i.e. as a local variable
 *  of a function which returns after starting a transfer).
 *
 * \param bEndpoint Endpoint number.
 * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes
 *             the buffer list to send.
 * \param wListSize Size of the frame list.
 * \param bCircList Circle the list.
 * \param wStartNdx For circled list only, the first buffer index to transfer.
 * \param fCallback Optional callback function to invoke when the transfer is
 *        complete.
 * \param pArgument Optional argument to the callback function.
 * \return USBD_STATUS_SUCCESS if the transfer has been started;
 *         otherwise, the corresponding error status code.
 * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse
 */
uint8_t USBD_MblWrite( uint8_t       bEndpoint,
                    void                *pMbl,
                    uint16_t      wListSize,
                    uint8_t       bCircList,
                    uint16_t      wStartNdx,
                    MblTransferCallback fCallback,
                    void                *pArgument )
{
    Endpoint    *pEndpoint = &(endpoints[bEndpoint]);
    MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
    uint16_t i;

    /* EP0 is not suitable for Mbl */

    if (bEndpoint == 0) {

        return USBD_STATUS_INVALID_PARAMETER;
    }

    /* Check that the endpoint is in Idle state */

    if (pEndpoint->state != UDP_ENDPOINT_IDLE) {

        return USBD_STATUS_LOCKED;
    }
    pEndpoint->state = UDP_ENDPOINT_SENDINGM;

    TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);

    /* Start from first if not circled list */

    if (!bCircList) wStartNdx = 0;

    /* Setup the transfer descriptor */

    pTransfer->pMbl        = (USBDTransferBuffer*)pMbl;
    pTransfer->listSize    = wListSize;
    pTransfer->fCallback   = fCallback;
    pTransfer->pArgument   = pArgument;
    pTransfer->currBuffer  = wStartNdx;
    pTransfer->freedBuffer = 0;
    pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
    pTransfer->circList    = bCircList;
    pTransfer->allUsed     = 0;

    /* Clear all buffer */

    for (i = 0; i < wListSize; i ++) {

        pTransfer->pMbl[i].transferred = 0;
        pTransfer->pMbl[i].buffered   = 0;
        pTransfer->pMbl[i].remaining   = pTransfer->pMbl[i].size;
    }

    /* Send the first packet */

    while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
    UDP_MblWriteFifo(bEndpoint);
    SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);

    /* If double buffering is enabled and there is data remaining, */

    /* prepare another packet */

    if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
        && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {

        UDP_MblWriteFifo(bEndpoint);
    }

    /* Enable interrupt on endpoint */

    UDP->UDP_IER = 1 << bEndpoint;

    return USBD_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
/// USB interrupt subroutine
///
/// This function is called each time a USB interrupt occurs.
/// The following USB DEVICE events are taken in charge:
/// - VBus On / Off
/// - Start Of Frame
/// - Suspend
/// - Wake-Up
/// - Resume
/// - Reset
/// - Start of frame
///
/// The following USB HOST events are taken in charge:
/// - Device connection
/// - Device Disconnection
/// - Start Of Frame
/// - ID pin change
/// - SOF (or Keep alive in low speed) sent
/// - Wake up on USB line detected
///
/// The following USB HOST events are taken in charge:
/// - HNP success (Role Exchange)
/// - HNP failure (HNP Error)
///
/// For each event, the user can launch an action by completing
/// the associate define (See conf_usb.h file to add action upon events)
///
/// Note: Only interrupts events that are enabled are processed
//------------------------------------------------------------------------------
void usb_general_interrupt(void)
{
    //TRACE_DEBUG("usb_general_interrupt\n\r");

    // ---------- DEVICE events management -----------------------------------
    // -----------------------------------------------------------------------

    //- VBUS state detection
    // -----------------------------------------------------------------------
    /// Arbitrer
    // -----------------------------------------------------------------------
    if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() 
        && Is_usb_id_device()) {
        Usb_ack_vbus_transition();

        if (Is_usb_vbus_high()) {
            usb_connected = TRUE;
            Usb_vbus_on_action();
            Usb_send_event(EVT_USB_POWERED);
            //jcb    Usb_enable_reset_interrupt();
            //usb_start_device();
            USBD_Connect();//Usb_attach();
        }
        else {
            TRACE_DEBUG("VBUS low\n\r");
            USBD_Disconnect();
            Usb_device_stop_hnp();
            TRACE_DEBUG("Usb_select_device4\n\r");
            Usb_select_device();
            Clear_all_user_request();
            Usb_vbus_off_action();
            usb_connected = FALSE;
            usb_configuration_nb = 0;
            Usb_send_event(EVT_USB_UNPOWERED);
        }

    }

    // -----------------------------------------------------------------------
    /// Device
    // -----------------------------------------------------------------------
    // - Device start of frame received
    if (Is_usb_sof() && Is_sof_interrupt_enabled()) {
        //  TRACE_DEBUG_WP("F");   // device
        Usb_ack_sof();
        Usb_sof_action();
        //sof_seen_in_session = TRUE;
        otg_last_sof_received = UDFNUML;  // store last frame number received
    }

    // -----------------------------------------------------------------------
    /// Device
    // -----------------------------------------------------------------------
    // - Device Suspend event (no more USB activity detected)
    if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) {
        //TRACE_DEBUG_WP("D\n\r");
        // 1st : B-PERIPH mode ?
        if (Is_usb_id_device()) {
            // HNP Handler
            TRACE_DEBUG("HNP Handler\n\r");
            //TRACE_DEBUG("device_state = %d\n\r", device_state);
            //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state);
            if (Is_host_requested_hnp() // "b_hnp_enable" feature received
            && (Is_session_started_with_srp() || Is_user_requested_hnp() )) {
                if (otg_device_nb_hnp_retry == 0) {
                    otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE;
                }
                else {
                    Ack_user_request_hnp();
                    Usb_ack_hnp_error_interrupt();
                    Usb_ack_role_exchange_interrupt();
                    Usb_enable_role_exchange_interrupt();
                    Usb_enable_hnp_error_interrupt();
                    Usb_device_initiate_hnp();
                    otg_device_nb_hnp_retry--;
                }
            }
            else
            {
                // Remote wake-up handler
                //TRACE_DEBUG("Remote wake-up handler\n\r");
                //TRACE_DEBUG("device_state = %d\n\r", device_state);
                //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state);
                if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0))
                {
                    //TRACE_DEBUG("enabled\n\r");
                    // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up
                    // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume
                    // So the SUSPE enable bit must be cleared to avoid redundant interrupt
                    // ****************
                    // Please note also that is Vbus is lost during an upstream resume (Host disconnection),
                    // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent)
                    // remains set after the event, so that a good way to handle this feature is :
                    //            Usb_initiate_remote_wake_up();
                    //            while (Is_usb_pending_remote_wake_up())
                    //            {
                    //              if (Is_usb_vbus_low())
                    //              {
                    //                // Emergency action (reset macro, etc.) if Vbus lost during resuming
                    //                break;
                    //              }
                    //            }
                    //            Usb_ack_remote_wake_up_start();
                    // ****************
                }
                else {
                    //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature);
                    // No remote wake-up supported
                    Usb_send_event(EVT_USB_SUSPEND);
                }
            }
        }
        else
        {
            //TRACE_DEBUG("ici\n\r");
            // A-PERIPH mode (will cause a session end, handled in usb_host_task.c)
            Usb_send_event(EVT_USB_SUSPEND);
            Usb_suspend_action();
            //jcb   Usb_ack_suspend();
        }
    }
   
    // -----------------------------------------------------------------------
    /// Device
    // -----------------------------------------------------------------------
    // - Wake up event (USB activity detected): Used to resume
    if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) {
        TRACE_DEBUG("W\n\r");
        Usb_unfreeze_clock();
        Usb_send_event(EVT_USB_WAKE_UP);
    }

    // -----------------------------------------------------------------------
    /// Device
    // -----------------------------------------------------------------------
    // - Resume state bus detection
    if (Is_usb_resume() && Is_resume_interrupt_enabled()) {
        TRACE_DEBUG("Resume state bus detect\n\r");
        Usb_send_event(EVT_USB_RESUME);
    }

    // -----------------------------------------------------------------------
    /// Device
    // -----------------------------------------------------------------------
    // - USB bus reset detection
    if (Is_usb_reset()&& Is_reset_interrupt_enabled()) {
        TRACE_DEBUG_WP("B\n\r");
        if (Is_usb_id_host()) {
            //TRACE_DEBUG_WP("id_host\n\r");
            dev_configure_endpoint(EP_CONTROL,
            TYPE_CONTROL,
            DIRECTION_OUT,
            SIZE_64,
            ONE_BANK,
            NYET_DISABLED);
        }
        // First initialization is important to be synchronized
        // A reset must first have been received
        if (device_state == A_PERIPHERAL) {
            //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r");
            otg_last_sof_received = UDFNUML;
            otg_last_sof_stored   = UDFNUML;
            Usb_ack_sof();
            Usb_enable_sof_interrupt();
            reset_received = TRUE;
            Timer16_set_counter(0);
        }
        Usb_reset_action();
        Usb_send_event(EVT_USB_RESET);
    }

    // ---------- OTG events management ------------------------------------
    // ---------------------------------------------------------------------

    // -----------------------------------------------------------------------
    /// Arbitrer
    // -----------------------------------------------------------------------
    // - OTG HNP Success detection
    if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) {
        //     TRACE_DEBUG("OTG HNP detect\n\r");
        Usb_ack_role_exchange_interrupt();
        Host_ack_device_connection();
        Host_ack_device_disconnection();
        Otg_send_event(EVT_OTG_HNP_SUCCESS);
        End_session_with_srp();
        Clear_otg_features_from_host();
        if (Is_usb_id_host()) {
            // HOST (A- or B-) mode
            if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) {
                static volatile unsigned int jcb;
                // Current mode is A-HOST, device will take the A-PERIPHERAL role
                b_uut_device_state = B_PERIPHERAL;
                device_state = A_PERIPHERAL;
                usb_connected = FALSE;
                usb_configuration_nb = 0;
                Usb_select_device();
                USBD_Connect();//Usb_attach();
                Usb_unfreeze_clock();
                Usb_disable_role_exchange_interrupt();
                Usb_disable_hnp_error_interrupt();
                Usb_device_stop_hnp();
                Usb_ack_reset();
                Timer16_set_counter(0);
                Usb_freeze_clock();                // USB clock can be freezed to slow down events and condition detection
                //jcb       while (Timer16_get_counter_low() != 20);
                jcb=0;
                while( jcb <100000){ jcb++; }

                Usb_unfreeze_clock();
                reset_received = FALSE;
                Usb_disable_sof_interrupt();       // will be set in the next OTG Timer IT (mandatory)

                Usb_enable_suspend_interrupt();
                Usb_enable_reset_interrupt();
                dev_configure_endpoint(EP_CONTROL,
                    TYPE_CONTROL,
                    DIRECTION_OUT,
                    SIZE_64,
                    ONE_BANK,
                    NYET_DISABLED);
            }
        }
        else {
            // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start)
            if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) {
                static volatile unsigned int jcb2;
                // Current mode is B-PERIPHERAL, device will go into B-HOST role
                End_session_with_srp();
                Clear_otg_features_from_host();
                b_uut_device_state = B_HOST;
                device_state = DEVICE_ATTACHED;
                usb_connected = FALSE;
                usb_configuration_nb = 0;
                TRACE_DEBUG("Select host 3\n\r");
                Usb_select_host();

                TRACE_DEBUG("Send reset\n\r");
                Host_send_reset();     // send the first RESET
                while (Host_is_reset());
                TRACE_DEBUG("Reset passed\n\r");

                jcb2=0;
                while( jcb2 <1000000){ jcb2++; }
                Host_enable_sof();     // start Host (sof)
                Usb_disable_role_exchange_interrupt();
                Usb_disable_hnp_error_interrupt();
                Clear_all_user_request();

                TRACE_DEBUG("Select host 3\n\r");
            }
        }
    }

    // -----------------------------------------------------------------------
    /// Arbitrer
    // -----------------------------------------------------------------------
    // - OTG HNP Failure detection
    if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) {
        TRACE_DEBUG("OTG HNP failure\n\r");
        Usb_device_stop_hnp();
        Usb_disable_role_exchange_interrupt();
        Usb_disable_hnp_error_interrupt();
        Usb_ack_hnp_error_interrupt();
        if (Is_usb_id_device()) {
            Otg_send_event(EVT_OTG_HNP_ERROR);
            Clear_all_user_request();
        }
    }   

    // ---------- HOST events management -----------------------------------
    // ---------------------------------------------------------------------

    // -----------------------------------------------------------------------
    /// Arbitrer
    // -----------------------------------------------------------------------
    // - ID pin change detection
    if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) {
        TRACE_DEBUG("ID pin change\n\r");
        TRACE_DEBUG("device_state = %d\n\r", device_state);
        TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state);
        Usb_device_stop_hnp();
        Clear_all_user_request();
        if(Is_usb_id_device()) { 
            g_usb_mode = USB_MODE_DEVICE;
        }
        else {
            g_usb_mode = USB_MODE_HOST;
        }
        Usb_ack_id_transition();
        if( g_usb_mode != g_old_usb_mode) { // Basic Debounce
            if(Is_usb_id_device()) { // Going into device mode
                Usb_send_event(EVT_USB_DEVICE_FUNCTION);
                b_uut_device_state = B_IDLE;
                device_state = DEVICE_UNATTACHED;
                id_changed_to_host_event = DISABLE;
            }
            else {                  // Going into host mode
                b_uut_device_state = B_IDLE;
                device_state = DEVICE_UNATTACHED;
                Usb_send_event(EVT_USB_HOST_FUNCTION);
                id_changed_to_host_event = ENABLE;
            }
            Usb_id_transition_action();
            TRACE_INFO("Pin Id changed\n\r");
        }
    }
   
    // -----------------------------------------------------------------------
    /// Host
    // -----------------------------------------------------------------------
    // - The device has been disconnected
    // JCB to be fix
    if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) {
        TRACE_DEBUG("device disconnect\n\r");
        host_disable_all_pipe();
        Host_ack_device_disconnection();
        device_state=DEVICE_DISCONNECTED;
        Usb_send_event(EVT_HOST_DISCONNECTION);
        TRACE_INFO("Device disconnected\n\r");
        Host_device_disconnection_action();
        Clear_all_user_request();
    }

    // -----------------------------------------------------------------------
    /// Host
    // -----------------------------------------------------------------------
    // - Device connection
    if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) {
        TRACE_DEBUG("device connect\n\r");
        Host_ack_device_connection();
        host_disable_all_pipe();
        Host_device_connection_action();
    }

    // -----------------------------------------------------------------------
    /// Host
    // -----------------------------------------------------------------------
    // - Host Start of frame has been sent
    if (Is_host_sof() && Is_host_sof_interrupt_enabled()) {
        //TRACE_DEBUG_WP("_");  // host
        Host_ack_sof();
        Usb_send_event(EVT_HOST_SOF);
        private_sof_counter++;

        // delay timeout management for interrupt tranfer mode in host mode
#if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE))
        if (private_sof_counter>=250) {  // Count 1/4 sec
            private_sof_counter=0;
            for(i=0;i<MAX_EP_NB;i++) {
                if(it_pipe_str[i].enable==ENABLE) {
                    save_pipe_nb=Host_get_selected_pipe();
                    Host_select_pipe(i);
                    if((++it_pipe_str[i].timeout>TIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) {
                        it_pipe_str[i].enable=DISABLE;
                        it_pipe_str[i].status=PIPE_DELAY_TIMEOUT;
                        Host_stop_pipe_interrupt(i);
                        if (is_any_interrupt_pipe_active()==FALSE) {   // If no more transfer is armed
                            if (g_sav_int_sof_enable==FALSE) {
                                Host_disable_sof_interrupt();
                            }
                        }
                        it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed);
                    }
                    Host_select_pipe(save_pipe_nb);
                }
            }
        }
#endif  // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE))
        Host_sof_action();
    }

    // -----------------------------------------------------------------------
    /// Host
    // -----------------------------------------------------------------------
    // - Host Wake-up has been received
    if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) {
        TRACE_DEBUG("Host wake up\n\r");
        Host_disable_hwup_interrupt();  // Wake up interrupt should be disable host is now wake up !
        Host_disable_remote_wakeup_interrupt();
        // CAUTION HWUP can be cleared only when USB clock is active (not frozen)!
        Usb_unfreeze_clock();           // Enable clock on USB interface
        Host_enable_sof();              // start sending SOF
        Host_ack_hwup();                // Clear HWUP interrupt flag
        Host_ack_remote_wakeup();
        Usb_send_event(EVT_HOST_HWUP);  // Send software event
        Usb_send_event(EVT_HOST_REMOTE_WAKEUP);
        Host_hwup_action();             // Map custom action
        if (Is_usb_hnp()) {
            Usb_host_reject_hnp();
            Usb_disable_hnp_error_interrupt();
            Usb_disable_role_exchange_interrupt();
        }
        Host_send_resume();
    }

    // -----------------------------------------------------------------------
    /// Host
    // -----------------------------------------------------------------------
    // Remote Wake Up has been received
    if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) {
        TRACE_DEBUG("Remote wake up\n\r");
        Host_disable_remote_wakeup_interrupt();
        Host_disable_hwup_interrupt();
        Host_ack_remote_wakeup();
        Host_ack_hwup();                // Clear HWUP interrupt flag
        Usb_unfreeze_clock();           // Enable clock on USB interface
        Host_enable_sof();     // start sending SOF
        Usb_send_event(EVT_HOST_REMOTE_WAKEUP);
        Usb_send_event(EVT_HOST_HWUP);  // Send software event
        if (Is_usb_hnp()) {
            Usb_host_reject_hnp();
            Usb_disable_hnp_error_interrupt();
            Usb_disable_role_exchange_interrupt();
        }
        Host_send_resume();
    }
}
/**
 * Sends the requested USB descriptor to the host if available, or STALLs  the
 * request.
 * \param pDriver  Pointer to a USBDDriver instance.
 * \param type  Type of the requested descriptor
 * \param index  Index of the requested descriptor.
 * \param length  Maximum number of bytes to return.
 */
static void GetDescriptor(
    const USBDDriver *pDriver,
    uint8_t type,
    uint8_t indexRDesc,
    uint32_t length)
{
    const USBDeviceDescriptor *pDevice;
    const USBConfigurationDescriptor *pConfiguration;
    const USBDeviceQualifierDescriptor *pQualifier;
    const USBConfigurationDescriptor *pOtherSpeed;
    const USBGenericDescriptor **pStrings =
        (const USBGenericDescriptor **) pDriver->pDescriptors->pStrings;
    const USBGenericDescriptor *pString;
    uint8_t numStrings = pDriver->pDescriptors->numStrings;
    uint8_t terminateWithNull = 0;

    /* Use different set of descriptors depending on device speed */

    /* By default, we uses full speed values */
    pDevice = pDriver->pDescriptors->pFsDevice;
    pConfiguration = pDriver->pDescriptors->pFsConfiguration;

    /* HS, we try HS values */
    if (USBD_HAL_IsHighSpeed()) {

        TRACE_DEBUG_WP("HS ");
        if (pDriver->pDescriptors->pHsDevice)
            pDevice = pDriver->pDescriptors->pHsDevice;
        if (pDriver->pDescriptors->pHsConfiguration)
            pConfiguration = pDriver->pDescriptors->pHsConfiguration;
        pQualifier = pDriver->pDescriptors->pHsQualifier;
        pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed;
    }
    else {

        TRACE_DEBUG_WP("FS ");
        pQualifier = pDriver->pDescriptors->pFsQualifier;
        pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed;
    }

    /* Check the descriptor type */

    switch (type) {

        case USBGenericDescriptor_DEVICE:
            TRACE_INFO_WP("Dev ");

            /* Adjust length and send descriptor */

            if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) {

                length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice);
            }
            USBD_Write(0, pDevice, length, 0, 0);
            break;

        case USBGenericDescriptor_CONFIGURATION:
            TRACE_INFO_WP("Cfg ");

            /* Adjust length and send descriptor */

            if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) {

                length = USBConfigurationDescriptor_GetTotalLength(pConfiguration);
                terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
            }
            USBD_Write(0,
                       pConfiguration,
                       length,
                       terminateWithNull ? TerminateCtrlInWithNull : 0,
                       0);
            break;

        case USBGenericDescriptor_DEVICEQUALIFIER:
            TRACE_INFO_WP("Qua ");

            /* Check if descriptor exists */

            if (!pQualifier) {

                USBD_Stall(0);
            }
            else {

                /* Adjust length and send descriptor */

                if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) {

                    length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier);
                }
                USBD_Write(0, pQualifier, length, 0, 0);
            }
            break;

        case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
            TRACE_INFO_WP("OSC ");

            /* Check if descriptor exists */

            if (!pOtherSpeed) {

                USBD_Stall(0);
            }
            else {

                /* Adjust length and send descriptor */

                if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) {

                    length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed);
                    terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
                }
                USBD_Write(0,
                           pOtherSpeed,
                           length,
                           terminateWithNull ? TerminateCtrlInWithNull : 0,
                           0);
            }
            break;

        case USBGenericDescriptor_STRING:
            TRACE_INFO_WP("Str%d ", indexRDesc);

            /* Check if descriptor exists */

            if (indexRDesc >= numStrings) {

                USBD_Stall(0);
            }
            else {

                pString = pStrings[indexRDesc];

                /* Adjust length and send descriptor */

                if (length > USBGenericDescriptor_GetLength(pString)) {

                    length = USBGenericDescriptor_GetLength(pString);
                    terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
                }
                USBD_Write(0,
                           pString,
                           length,
                           terminateWithNull ? TerminateCtrlInWithNull : 0,
                           0);
            }
            break;

        default:
            TRACE_WARNING(
                      "USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r",
                      type);
            USBD_Stall(0);
    }
}