/** \brief Internal function used for the very similar \ref SET_FEATURE and \ref CLEAR_FEATURE requests
 *
 * This function either sets or clears the specified feature on the specified recipient.
 *
 * \param[in]       set
 *     When TRUE, the feature is set. When FALSE, the feature is cleared.
 *
 * \return
 *     TRUE if the selected feature is supported by the USB library. FALSE to indicate that
 *     \ref usbsrHookClearFeature() or \ref usbsrHookSetFeature() must be called.
 */
static uint8 ChangeFeature(uint8 set)
{
   uint8 endpoint;

   // Sanity check
   if (usbSetupHeader.length || (usbfwData.usbState != DEV_CONFIGURED) && (usbSetupHeader.index != 0)) {
      usbfwData.ep0Status = EP_STALL;

      // Handle based on recipient
   } else {
      switch (usbSetupHeader.requestType & RT_MASK_RECIP) {

      // Device
      case RT_RECIP_DEV:

         // Sanity check
         if (LO_UINT16(usbSetupHeader.value) != DEVICE_REMOTE_WAKEUP) {
            return FALSE;
         } else {
            usbfwData.remoteWakeup = set;
            usbsrHookProcessEvent(set ? USBSR_EVENT_REMOTE_WAKEUP_ENABLED : USBSR_EVENT_REMOTE_WAKEUP_DISABLED, 0);
         }
         break;

      // Endpoint
      case RT_RECIP_IF:
         return FALSE;

      // Endpoint
      case RT_RECIP_EP:
         endpoint = LO_UINT16(usbSetupHeader.index) & 0x7F;

         // Sanity check
         if (LO_UINT16(usbSetupHeader.value) != ENDPOINT_HALT) {
            return FALSE;
         } else if (endpoint > 5) {
            usbfwData.ep0Status = EP_STALL;
         } else {
            USBFW_SELECT_ENDPOINT(endpoint);

            // IN
            if (LO_UINT16(usbSetupHeader.index) & 0x80) {
               USBCSIL = set ? USBCSIL_SEND_STALL : USBCSIL_CLR_DATA_TOG;
               usbfwData.pEpInStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE;
               usbsrHookProcessEvent(set ? USBSR_EVENT_EPIN_STALL_SET : USBSR_EVENT_EPIN_STALL_CLEARED, endpoint);

            // OUT
            } else {
               USBCSOL = set ? USBCSOL_SEND_STALL : USBCSOL_CLR_DATA_TOG;
               usbfwData.pEpOutStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE;
               usbsrHookProcessEvent(set ? USBSR_EVENT_EPOUT_STALL_SET : USBSR_EVENT_EPOUT_STALL_CLEARED, endpoint);
            }
            USBFW_SELECT_ENDPOINT(0);
         }
         break;

      default:
         usbfwData.ep0Status = EP_STALL;
         break;
      }
   }
   return TRUE;
} // ChangeFeature
예제 #2
0
/** \brief Internal function used for the very similar \c SET_FEATURE and \c CLEAR_FEATURE requests
 *
 * This function either sets or clears the specified feature on the specified recipient.
 *
 * \param[in]       set
 *     When TRUE, the feature is set. When FALSE, the feature is cleared.
 *
 * \return
 *     TRUE if the selected feature is supported by the USB library. FALSE to indicate that
 *     \ref usbsrHookClearFeature() or \ref usbsrHookSetFeature() must be called.
 */
static uint8_t usbsrChangeFeature(uint8_t set)
{
    uint8_t endpoint;
    
    //
    // Sanity check
    //
    if(usbSetupHeader.length || ((usbfwData.usbState != DEV_CONFIGURED) && (usbSetupHeader.index != 0)))
    {
        usbfwData.ep0Status = EP_STALL;
        //
        // Handle based on recipient
        //
    }
    else
    {
        switch(usbSetupHeader.requestType & RT_MASK_RECIP)
        {
            //
            // Device
            //
        case RT_RECIP_DEV:
            
            //
            // Sanity check
            //
            if(usbSetupHeader.valueLsb != USBSR_FEATSEL_DEVICE_REMOTE_WAKEUP)
            {
                return false;
            }
            else
            {
                usbfwData.remoteWakeup = set;
                usbsrHookProcessEvent(set ? USBSR_EVENT_REMOTE_WAKEUP_ENABLED : USBSR_EVENT_REMOTE_WAKEUP_DISABLED, 0);
            }
            break;
            //
            // Interface
            //
        case RT_RECIP_IF:
            return false;

            //
            // Endpoint
            //
        case RT_RECIP_EP:
            endpoint = usbSetupHeader.indexLsb & 0x7F;
            
            //
            // Sanity check
            //
            if(usbSetupHeader.valueLsb != USBSR_FEATSEL_ENDPOINT_HALT)
            {
                return false;
            }
            else if(endpoint > 5)
            {
                usbfwData.ep0Status = EP_STALL;
            }
            else
            {
                USBFW_SELECT_ENDPOINT(endpoint);
                
                //
                // IN
                //
                if(usbSetupHeader.indexLsb & 0x80)
                {
                    HWREG(USB_CS0_CSIL) = set ? USB_CSIL_SENDSTALL_M : USB_CSIL_CLRDATATOG_M;
                    usbfwData.pEpInStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE;
                    usbsrHookProcessEvent(set ? USBSR_EVENT_EPIN_STALL_SET : USBSR_EVENT_EPIN_STALL_CLEARED, endpoint);
                    
                    //
                    // OUT
                    //
                }
                else
                {
                    HWREG(USB_CSOL) = set ? USB_CSOL_SENDSTALL_M : USB_CSOL_CLRDATATOG_M;
                    usbfwData.pEpOutStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE;
                    usbsrHookProcessEvent(set ? USBSR_EVENT_EPOUT_STALL_SET : USBSR_EVENT_EPOUT_STALL_CLEARED, endpoint);
                }
                USBFW_SELECT_ENDPOINT(0);
            }
            break;

        default:
            usbfwData.ep0Status = EP_STALL;
            break;
        }
    }
    return true;
}