//-----------------------------------------------------------------------------
// F320_USB_Standard_Requests.c
//-----------------------------------------------------------------------------
// Copyright 2006 Silicon Laboratories, Inc.
// http://www.silabs.com
//
// Program Description:
//
// This is the module that handles USB standard requests.  These requests are
// defined in chapter nine of the USB specification.
//
// FID:            32X000030
// Target:         C8051F320
// Tool chain:     KEIL C51 7.0.0.1
//                 Silicon Laboratories IDE version 2.3
// Command Line:   See Readme.txt
// Project Name:   F320_FM_Radio
//
// Release 1.1
//    -No changes made to this module (DM)
//    -16 JAN 2006
//
// Release 1.0
//    -Initial Revision (DM)
//    -05 APR 2002
//

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------

#include "c8051f320.h"                 // SFR declarations
#include "F320_FM_RadioMain.h"         // Main project header
#include "F320_USB_Register.h"         // USB core register header
#include "F320_USB_Common.h"           // USB protocol header
#include "F320_USB_Descriptor.h"       // USB descriptor definitions

//-----------------------------------------------------------------------------
// Variable Declaration
//-----------------------------------------------------------------------------

idata BYTE Selected_Interface1;

//-----------------------------------------------------------------------------
// Get_Status
//
// Return Value : None
// Parameters   : None
//
// Returns status information for a given device, interface, or endpoint by
// sending a two byte status packet to the host.
//
//-----------------------------------------------------------------------------
void Get_Status (void) using USB_REGISTER_BANK
{
   // If non-zero return length or data length not equal to 2 then send a stall
   // indicating invalid request
   if ((Setup.wValue.i != 0) || (Setup.wLength.i != 2))
   {                                            
      Force_Stall ();
   }

   switch (Setup.bmRequestType)        // Determine intended recipient
   {
      case OUT_DEVICE:                 // If recipient was device
         // Stall if invalid request otherwise send 0x0000, indicating bus
         // power and no remote wake-up
         if (Setup.wIndex.i != 0) Force_Stall();
         else DataPtr = (BYTE*)&ZERO_PACKET;
         break;
      
      case OUT_INTERFACE:              // See if recipient was interface
         // Send stall if invalid command otherwise return 0x0000
         if ((USB_State != DEV_CONFIGURED) || (Setup.wIndex.i != 0)) 
         {
            Force_Stall();             
         }
         else DataPtr = (BYTE*)&ZERO_PACKET;
         break;
  
      case OUT_ENDPOINT:               // See if recipient was an endpoint
         // Make sure device is configured and index msb = 0x00 otherwise
         // return stall to host
         if ((USB_State != DEV_CONFIGURED) || (Setup.wIndex.c[MSB]))          
         {
            Force_Stall();                      
         }
         else
         {
            switch (Setup.wIndex.c[LSB])
            {
               case IN_EP1:
                  if (Ep_Status[1] == EP_HALT) DataPtr = (BYTE*)&ONES_PACKET;
                  else DataPtr = (BYTE*)&ZERO_PACKET;
                  DataSize = 2;
                  break;

               case OUT_EP2:
                  if (Ep_Status[2] == EP_HALT) DataPtr = (BYTE*)&ONES_PACKET;
                  else DataPtr = (BYTE*)&ZERO_PACKET;
                  DataSize = 2;
                  break;

               case IN_EP3:
                  if (Ep_Status[3] == EP_HALT) DataPtr = (BYTE*)&ONES_PACKET;
                  else DataPtr = (BYTE*)&ZERO_PACKET;
                  DataSize = 2;
                  break;

               default: Force_Stall (); break;

            }
         }
         break;

      default:
         Force_Stall ();
         break;
   }

   if (Ep_Status[0] != EP_STALL)
   {
      // Set serviced setup packet bit, put endpoint in transmit mode, reset
      // data sent counter to 0 set data size to 2
      POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
      Ep_Status[0] = EP_TX;
      DataSent = 0;
      DataSize = 2;
   }
}

//-----------------------------------------------------------------------------
// Clear_Feature
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine can clear Halt Endpoint features for data endpoints.
//
//-----------------------------------------------------------------------------
void Clear_Feature (void) using USB_REGISTER_BANK 
{
   // Make sure device is configured, endpoint is recipient, and halt endpoint
   // feature is selected
   if ((USB_State != DEV_CONFIGURED) || (Setup.bmRequestType != IN_ENDPOINT) ||
   (Setup.wValue.i != ENDPOINT_HALT) || (Setup.wLength.i != 0))
   {
      Force_Stall ();                  // Otherwise send stall to host
   }
   else
   {             
      switch (Setup.wIndex.c[LSB])
      {
         case IN_EP1:
            POLL_WRITE_BYTE (INDEX, 1);
            // Clear feature endpoint 1 halt
            POLL_WRITE_BYTE (EINCSR1, rbInCLRDT);
            Ep_Status[1] = EP_IDLE;    // Set endpoint 1 status back to idle 
            break;

         case OUT_EP2:
            POLL_WRITE_BYTE (INDEX, 2);
            // Clear feature endpoint 2 halt
            POLL_WRITE_BYTE (EOUTCSR1, rbOutCLRDT);
            Ep_Status[2] = EP_IDLE;    // Set endpoint 2 status back to idle 
            break;

         case IN_EP3:
            POLL_WRITE_BYTE (INDEX, 3);
            // Clear feature endpoint 3 halt
            POLL_WRITE_BYTE (EINCSR1, rbInCLRDT);
            Ep_Status[3] = EP_IDLE;    // Set endpoint 3 status back to idle 
            break;

         default: Force_Stall (); break;

      }
   }
   POLL_WRITE_BYTE (INDEX, 0);         // Reset Index to 0

   // Indicate setup packet has been serviced
   if (Ep_Status[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
}

//-----------------------------------------------------------------------------
// Set_Feature
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine will set the EP Halt feature for data endpoints
//
//-----------------------------------------------------------------------------
void Set_Feature (void) using USB_REGISTER_BANK
{
   // Make sure device is configured, endpoint is recipient, and halt endpoint
   // feature is selected
   if ((USB_State != DEV_CONFIGURED) || (Setup.bmRequestType != IN_ENDPOINT) ||
   (Setup.wValue.i != ENDPOINT_HALT) || (Setup.wLength.i != 0))
   {
      Force_Stall ();                  // Otherwise send stall to host
   }
   else
   {
      switch (Setup.wIndex.c[LSB])
      {
         case IN_EP1:
            POLL_WRITE_BYTE (INDEX, 1);
            // Set feature endpoint 1 halt
            POLL_WRITE_BYTE (EINCSR1, rbInSDSTL);
            Ep_Status[1] = EP_HALT;    // Set endpoint 1 status to halt 
            break;

         case OUT_EP2:
            POLL_WRITE_BYTE (INDEX, 2);
            // Set feature endpoint 2 halt
            POLL_WRITE_BYTE (EOUTCSR1, rbOutSDSTL);
            Ep_Status[2] = EP_HALT;    // Set endpoint 2 status to halt 
            break;

         case IN_EP3:
            POLL_WRITE_BYTE (INDEX, 3);
            // Set feature endpoint 3 halt
            POLL_WRITE_BYTE (EINCSR1, rbInSDSTL);
            Ep_Status[3] = EP_HALT;    // Set endpoint 3 status to halt  
            break;

         default: Force_Stall (); break;

      }
   }   
   POLL_WRITE_BYTE (INDEX, 0);         // Reset Index to 0

   // Indicate setup packet has been serviced
   if (Ep_Status[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
}

//-----------------------------------------------------------------------------
// Set_Address
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Set new function address
//
//-----------------------------------------------------------------------------
void Set_Address (void) using USB_REGISTER_BANK
{
   // Request must be directed to device with index and length set to zero
   if ((Setup.bmRequestType != IN_DEVICE) || (Setup.wIndex.i != 0) ||
   (Setup.wLength.i != 0) || (Setup.wValue.i > 127))
   {
     Force_Stall();                    // Send stall if setup data invalid
   }

   // Set endpoint zero status to update address next status phase
   Ep_Status[0] = EP_ADDRESS;

   // Indicate that device state is now addressed or
   // If new address was 0x00, return device to default state
   if (Setup.wValue.c[LSB] != 0) USB_State = DEV_ADDRESS;
   else USB_State = DEV_DEFAULT;

   // Indicate setup packet has been serviced
   if (Ep_Status[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
}

//-----------------------------------------------------------------------------
// Get_Descriptor
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine sets the data pointer and size to correct descriptor and sets
// the endpoint status to transmit mode.
//
//-----------------------------------------------------------------------------
void Get_Descriptor (void) using USB_REGISTER_BANK
{
   // Determine which type of descriptor was requested, set data ptr and size
   switch (Setup.wValue.c[MSB])
   {
      case DSC_DEVICE:
         DataPtr = (BYTE*) &DeviceDesc;
         DataSize = DeviceDesc.bLength;
         break;
      
      case DSC_CONFIG:
         DataPtr = (BYTE*) &ConfigDesc;
         // Compiler Specific - the next statement reverses bytes in the
         // configuration descriptor for the compiler
         DataSize = (ConfigDesc.cd.wTotalLength.c[MSB] + 
         256*ConfigDesc.cd.wTotalLength.c[LSB]);
         break;
      
      case DSC_STRING:                 // Can have a maximum of 255 strings
         DataPtr = StringDescTable[Setup.wValue.c[LSB]];
         DataSize = *DataPtr;
         break;

      case DSC_HID_CLASS:              // HID Specific (HID class descriptor)
		   DataPtr = (BYTE*) &ConfigDesc.hd;
		   DataSize = ConfigDesc.hd.bLength;
		   break;

	   case DSC_HID_REPORT:             // HID Specific (HID report descriptor)
		   DataPtr = (BYTE*) &HidReportDesc;
		   DataSize = HID_REPORT_SIZE;
		   break;
      
      default:
         Force_Stall ();               // Send Stall if unsupported request
         break;
   }
   
   // Send only requested amount of data
   if (Setup.wLength.i < DataSize) DataSize = Setup.wLength.i;

   if (Ep_Status[0] != EP_STALL)
   {
      // Set serviced setup packet bit, put endpoint in transmit mode and reset
      // data sent counter
      POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
      Ep_Status[0] = EP_TX;
      DataSent = 0;
   }
}

//-----------------------------------------------------------------------------
// Get_Configuration
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine returns current configuration value.
//
//-----------------------------------------------------------------------------
void Get_Configuration (void) using USB_REGISTER_BANK
{
   // This request must be directed to the device with value word and index set
   // to zero, and setup length set to one
   if ((Setup.bmRequestType != OUT_DEVICE) || (Setup.wValue.i != 0) ||
   (Setup.wIndex.i != 0) || (Setup.wLength.i != 1))
   {
      Force_Stall ();                  // Otherwise send a stall to host
   }

   else 
   {
      DataSize = 1;
      // If the device is configured return 0x01 since this software supports
      // one configuration, otherwise return 0x00 since it isn't configured
      if (USB_State == DEV_CONFIGURED) DataPtr = (BYTE*)&ONES_PACKET;
      else DataPtr = (BYTE*)&ZERO_PACKET;
   }

   if (Ep_Status[0] != EP_STALL)
   {
      // Set serviced setup packet bit, put endpoint in transmit mode and reset
      // data sent counter
      POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
      Ep_Status[0] = EP_TX;
      DataSent = 0;
   }
}

//-----------------------------------------------------------------------------
// Set_Configuration
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine allows host to change current device configuration value.
//
//-----------------------------------------------------------------------------
void Set_Configuration (void) using USB_REGISTER_BANK
{
   // Device must be addressed before configured and request recipient must be
   // the device, the index and length words must be zero
   // Verify configuration is set to 0 or 1
   if ((USB_State == DEV_DEFAULT) || (Setup.bmRequestType != IN_DEVICE) ||
   (Setup.wIndex.i != 0) || (Setup.wLength.i != 0) ||  (Setup.wValue.i > 1))
   {
      Force_Stall();                   // Send stall if setup data is invalid
   }
   else
   {
      if (Setup.wValue.c[LSB] > 0)
      {
         USB_State = DEV_CONFIGURED;
         Ep_Status[1] = EP_IDLE;       // Set endpoint status to idle (enabled)
         Ep_Status[2] = EP_IDLE;
         Ep_Status[3] = EP_IDLE;

         POLL_WRITE_BYTE (INDEX, 1);   // Change index to endpoint 1
		   // Set endpoint in direction with interrupt settings
         POLL_WRITE_BYTE (EINCSR2, rbInDIRSEL);

         POLL_WRITE_BYTE (INDEX, 2);   // Change index to endpoint 2
		   // Set endpoint out direction with double buffered interrupt settings
         POLL_WRITE_BYTE (EOUTCSR2, rbOutDBOEN);

         POLL_WRITE_BYTE (INDEX, 3);   // Change index to endpoint 3
		   // Set endpoint in direction with isochronous settings
         POLL_WRITE_BYTE (EINCSR2, rbInDIRSEL | rbInISO);
         POLL_WRITE_BYTE (INDEX, 0);   // Set index back to endpoint 0
      }
      else
      {
         USB_State = DEV_ADDRESS;      // Unconfigures device by setting state
         Ep_Status[1] = EP_HALT;       // to address, and changing endpoints
         Ep_Status[2] = EP_HALT;       // status to halt
         Ep_Status[3] = EP_HALT;
      }
   }

   // Indicate setup packet has been serviced   
   if (Ep_Status[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
}

//-----------------------------------------------------------------------------
// Get_Interface
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine returns the currently selected interface.
//
//-----------------------------------------------------------------------------
void Get_Interface (void) using USB_REGISTER_BANK
{
   // If device is not configured or recipient is not an interface or non-zero
   // value field or data length not equal to one
   if ((USB_State != DEV_CONFIGURED) || (Setup.wValue.i != 0) ||
   (Setup.bmRequestType != OUT_INTERFACE) || (Setup.wLength.i != 1))
   {
      Force_Stall ();                  // Then return stall to host
   }

   else
   {
      DataSize = 1;
      if ((Setup.wIndex.i == 0) || (Setup.wIndex.i == 2)) 
      {
         // Return 0x00 to host
         DataPtr = (BYTE*)&ZERO_PACKET;
      }
      else
      {
         if (Setup.wIndex.i == 1) DataPtr = (BYTE*)&Selected_Interface1;
         else Force_Stall ();
      }
   }

   if (Ep_Status[0] != EP_STALL)
   {
      // Set serviced setup packet bit, put endpoint in transmit mode and reset
      // data sent counter
      POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
      Ep_Status[0] = EP_TX;
      DataSent = 0;
   }
}

//-----------------------------------------------------------------------------
// Set_Interface
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine allows the host to change the selected interface.
//
//-----------------------------------------------------------------------------
void Set_Interface (void) using USB_REGISTER_BANK
{
   // Make sure request is correct length and is directed at interface
   if ((Setup.bmRequestType != IN_INTERFACE) || (Setup.wLength.i != 0))
   {
      Force_Stall ();                  // Otherwise send a stall to host
   }
   else
   {
      if (Setup.wIndex.i == 1) Selected_Interface1 = (BYTE)Setup.wValue.i;
   }

   // Indicate setup packet has been serviced
   if (Ep_Status[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, rbSOPRDY);
}

//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------