/*************************************************************************
 * DISCLAIMER *
 * Services performed by FREESCALE in this matter are performed          *
 * AS IS and without any warranty. CUSTOMER retains the final decision   *
 * relative to the total design and functionality of the end product.    *
 * FREESCALE neither guarantees nor will be held liable by CUSTOMER      *
 * for the success of this project. FREESCALE disclaims all warranties,  *
 * express, implied or statutory including, but not limited to,          *
 * implied warranty of merchantability or fitness for a particular       *
 * purpose on any hardware, software ore advise supplied to the project  *
 * by FREESCALE, and or any product resulting from FREESCALE services.   *
 * In no event shall FREESCALE be liable for incidental or consequential *
 * damages arising out of this agreement. CUSTOMER agrees to hold        *
 * FREESCALE harmless against any and all claims demands or actions      *
 * by anyone on account of any damage, or injury, whether commercial,    *
 * contractual, or tortuous, rising directly or indirectly as a result   *
 * of the advise or assistance supplied CUSTOMER in connection with      *
 * product, services or goods supplied under this Agreement.             *
 *************************************************************************/
/*************************************************************************************************
 * File name   : Usb_Setup_Pkt.c
 *
 * Description : This file deal all events on endpoint 0 in enumeration process
 *               
 *
 * History     :
 * 04/01/2007  : Initial Development
 * 
 *************************************************************************************************/
#include <MC9S08JM60.h>
#include "Bootloader_Bdt.h"

#include "Bootloader_Drv.h"
#include "Bootloader_Descriptor.h"
#include "Bootloader_Hid.h"




/*Local variable definition    */
byte Ctrl_Trf_State;                 /* Control Transfer State*/

/* Global variable definition  */
byte Ctrl_Trf_Session_Owner;         /* Current transfer session owner*/
byte *pSrc;                       /* Data source pointer*/
byte *pObj;                       /* Data destination pointer*/
int Transfer_Cnt;                /* Data counter*/


extern  volatile const sd000;
extern  volatile const sd001;
extern  volatile const sd002;


/* Local functions definition */
void USB_CtrlTrf_SetupStage_Processing(void);
void USB_CtrlEP_SetupStage_Complete(void);

void USB_CtrlTrf_OUT_Handler(void);
void USB_CtrlTrf_IN_Handler(void);

void USB_CtrlTrf_RxData(void);
void USB_CtrlTrf_TxData(void);

void USB_StdReq_Handler(void);
void USB_ClassReq_Handler(void);
void USB_StdGetDsc_Handler(void);
void USB_StdSetCfg_Handler(void);
void USB_StdGetStatus_Handler(void);
void USB_StdFeatureReq_Handler(void);


/* Global functions definition  */
void USB_Transaction_Handler(void);
void USB_Prepare_Next_Trf(void);


/******************************************************************************
 * Function:        void USB_CtrlEP_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        process the transaction from different endpoint
 *****************************************************************************/
void USB_Transaction_Handler(void)
{   
   unsigned char stat = STAT;
    
   if((stat & 0xF0 )  == 0x00)
   {
     stat &= 0xF8;  
    
     if(stat == EP00_OUT)
      {
        if(Bdtmap.ep0Bo.Stat.RecPid.PID == SETUP_TOKEN)    
            USB_CtrlTrf_SetupStage_Processing();
        else                                              
            USB_CtrlTrf_OUT_Handler();
      }
     else 
      {
        if(stat == EP00_IN)                                 
          USB_CtrlTrf_IN_Handler();
      }
   }
}

/******************************************************************************
 * Function:        void USB_CtrlTrf_OUT_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function handles an OUT transaction according to
 *                  which control transfer state is currently active.
 *****************************************************************************/
void USB_CtrlTrf_OUT_Handler(void)
{
    if(Ctrl_Trf_State == CTL_TRF_DATA_RX)
        USB_CtrlTrf_RxData();                            /*Data stage*/
    else    
        USB_Prepare_Next_Trf();                          /*Current transfer completes*/
   
}


/******************************************************************************
 * Function:        void USB_CtrlTrf_RxData(void)
 * Input:           None
 *
 * Output:          None
 * Overview:        
 * Note:            None
 *****************************************************************************/
void USB_CtrlTrf_RxData(void)
{
    int Byte_Num;

    Byte_Num = (int)Bdtmap.ep0Bo.Cnt;
    
    Transfer_Cnt = Transfer_Cnt + Byte_Num;
    pSrc = (byte*)&CtrlTrf_Data;

    while(Byte_Num)
    {
        *pObj = *pSrc;			/*Please init the pObj when receiving data in enumeration process*/
        pObj++;
        pSrc++;
        Byte_Num--;
    }

  if (Ctrl_Trf_Session_Owner == HID_CLASS_ID){
    HID_Rec_Data();
                Bdtmap.ep0Bi.Cnt = 0;           
      	    Bdtmap.ep0Bi.Addr = 0x08;         /*can calculate the addree according the offset in Bdtmap*/
            Bdtmap.ep0Bi.Stat._byte = _SIE|_DATA1|_DTS;

  }
  
   if(Bdtmap.ep0Bo.Stat.McuCtlBit.DTS == 0)
     Bdtmap.ep0Bo.Stat._byte = _SIE|_DATA1|_DTS;
   else
     Bdtmap.ep0Bo.Stat._byte = _SIE|_DATA0|_DTS;  
  
}

 
 /******************************************************************************
 * Function:        void USB_CtrlTrf_IN_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function handles an IN transaction according to
 *                  which controls transfer state is currently active.
 *                  It will check if it is the set-address transaction
 *
 *****************************************************************************/
void USB_CtrlTrf_IN_Handler(void)
{
   if(Usb_Device_State == ADDR_PENDING_STATE)
    {
      ADDR = Setup_Pkt.CtlAdd.bDevADR._byte;
                              
      if(ADDR > 0x00)
        Usb_Device_State = ADDRESS_STATE; 
      else
        Usb_Device_State = DEFAULT_STATE; 
    }
    
    if(Ctrl_Trf_State == CTL_TRF_DATA_TX)
      USB_CtrlTrf_TxData();
    else 
      USB_Prepare_Next_Trf();
   
}

/******************************************************************************
 * Function:        void USB_CtrlTrf_TxData(void)
 * Input:           None
 * Output:          None
 * Overview:       
 *
 *****************************************************************************/
void USB_CtrlTrf_TxData(void)
{    
    int Byte_To_Send;
    
    
    if (Transfer_Cnt==0){
       Bdtmap.ep0Bo.Cnt = EP0_BUFF_SIZE;
       Bdtmap.ep0Bo.Addr = 0x0C;         /*can calculate the addree according the offset in Bdtmap*/
       Bdtmap.ep0Bo.Stat._byte = _SIE;         
    }
      
    
    if(Transfer_Cnt < EP0_BUFF_SIZE){
        Byte_To_Send = Transfer_Cnt;
    }
    
    else
        Byte_To_Send = EP0_BUFF_SIZE;
    
    Bdtmap.ep0Bi.Cnt = (byte)(Byte_To_Send);
    
    Transfer_Cnt = Transfer_Cnt - Byte_To_Send;
    
    pObj = (byte*)&CtrlTrf_Data;               

    while(Byte_To_Send)
      {
          *pObj = *pSrc;
          pObj++;
          pSrc++;
          Byte_To_Send--;
      }
      
    if(Ctrl_Trf_State == CTL_TRF_DATA_TX)
     {
      if(Bdtmap.ep0Bi.Stat.McuCtlBit.DATA == 0)
        Bdtmap.ep0Bi.Stat._byte = _SIE|_DATA1|_DTS;
      else
        Bdtmap.ep0Bi.Stat._byte = _SIE|_DATA0|_DTS;  
     }
}

/******************************************************************************
 * Function:        void USB_CtrlTrf_SetupStage_Processing(void)
 *
 * Input:           None
 *
 * Output:          None
 *
 * Overview:        This function has 3 steps
 *                  1. init the control transfer state machine.
 *                  2. calls on each of the module that may know how to
 *                     service the Setup Request from the host.
 *                  3. Once each of the modules has a chance to check if
 *                     it is responsible for servicing the request
 *                     then checks direction of the transfer to determine how
 *                     to prepare EP0 for control transfer.
 *
 *****************************************************************************/
void USB_CtrlTrf_SetupStage_Processing(void)
{
    Transfer_Cnt = 0;
    Ctrl_Trf_State = WAIT_SETUP;
    Ctrl_Trf_Session_Owner = CLASS_NULL;    
    
    USB_StdReq_Handler();  
    
//    if(Ctrl_Trf_Session_Owner == CLASS_NULL)     /*if it is not USB standard request*/
//      USB_ClassReq_Handler();                    /*verify if it is class request*/
      HID_Class_Request_Handler();

    
    USB_CtrlEP_SetupStage_Complete();          
    
}



/******************************************************************************
 * Function:        void USB_CtrlEP_SetupStage_Complete(void)
 * Input:           None
 *
 * Output:          None
 * Overview:        This function wrap up the ramaining tasks in servicing
 *                  a Setup Request. Its main task is to set the endpoint
 *                  controls appropriately for a given situation. 
 *****************************************************************************/
void USB_CtrlEP_SetupStage_Complete(void)
{
	int Tmp;
   
  if(Ctrl_Trf_Session_Owner == CLASS_NULL)
    {
        Bdtmap.ep0Bo.Cnt = EP0_BUFF_SIZE;
        Bdtmap.ep0Bo.Addr = 0x0C;             /*can calculate the address according the offset in Bdtmap*/
        
        /*We can set the EPSTALL bit in EPCTL or the STALL bit in BDT register*/
        /*EPCTL0_EPSTALL = 1;*/
        Bdtmap.ep0Bo.Stat._byte = _SIE|_BDTSTALL;
        Bdtmap.ep0Bi.Stat._byte = _SIE|_BDTSTALL;
    }
   else    
    {
        if(Setup_Pkt.CtlReqT.DataDir == DEV_TO_HOST)
          {
          	Tmp = ((LSB(Setup_Pkt.CtlPara.W_Length)<<8) | (MSB(Setup_Pkt.CtlPara.W_Length))); //adjust endian

  		      if(Tmp < Transfer_Cnt)
                  Transfer_Cnt = Tmp;
  			
            USB_CtrlTrf_TxData();
            Ctrl_Trf_State = CTL_TRF_DATA_TX;
            Bdtmap.ep0Bi.Addr = 0x08;         /*can calculate the addree according the offset in Bdtmap*/
            Bdtmap.ep0Bi.Stat._byte = _SIE|_DATA1|_DTS;
          }
        else    
          {
            Ctrl_Trf_State = CTL_TRF_DATA_RX;
            
            if (Setup_Pkt.StdCtl.wLength==0){
             
            Bdtmap.ep0Bi.Cnt = 0;           
      	    Bdtmap.ep0Bi.Addr = 0x08;         /*can calculate the addree according the offset in Bdtmap*/
            Bdtmap.ep0Bi.Stat._byte = _SIE|_DATA1|_DTS;
            }

            Bdtmap.ep0Bo.Cnt = EP0_BUFF_SIZE;
            Bdtmap.ep0Bo.Addr = 0x0C;         /*can calculate the addree according the offset in Bdtmap*/
            Bdtmap.ep0Bo.Stat._byte = _SIE|_DATA1|_DTS;
          }
    }
    
    CTL_TSUSPEND = 0;
    
    return;
}


/******************************************************************************
 * Function:        void USB_Prepare_Next_Trf(void)
 * Input:           None
 * Output:          None
 * Overview:        The routine forces endpoint 0 OUT to be ready for a new Setup
 *                  transaction, and forces endpoint0 IN to be owned by MCU.
 * Note:            None
 *****************************************************************************/
void USB_Prepare_Next_Trf(void)
{
    Bdtmap.ep0Bo.Cnt = EP0_BUFF_SIZE;             
    Bdtmap.ep0Bo.Addr = 0x0C;         //((byte)(((byte*) &Setup_Pkt)-0x1880) >> 2 );   //
    Bdtmap.ep0Bo.Stat._byte = _SIE|_DATA0|_DTS; 
    Bdtmap.ep0Bi.Stat._byte = _CPU; 
    
    CTL_TSUSPEND = 0;
    Ctrl_Trf_State = WAIT_SETUP;            

    return;              
}


pFunc pStd_Req_Handler[] = { &USB_StdGetStatus_Handler };



/******************************************************************************
 * Function:        void USB_StdReq_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function checks the setup data packet to see if it
 *                  knows how to handle it
 * Note:            None
 *****************************************************************************/
void USB_StdReq_Handler(void)
{   
    if(Setup_Pkt.CtlReqT.RequestType != STANDARD) 
    	return;
    
    switch(Setup_Pkt.StdCtl.bRequest)
    {
       case GET_STATUS:         // 0
            USB_StdGetStatus_Handler();
              break;

        case CLR_FEATURE:       // 1
        case SET_FEATURE:       // 3
            USB_StdFeatureReq_Handler();
            break;

        case SET_ADR:           // 5
            Usb_Device_State = ADDR_PENDING_STATE;       
            Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
            break;

        case GET_DSC:           // 6
            USB_StdGetDsc_Handler();
            break;
    
         case GET_CFG:          // 8
            pSrc = (byte*)&Usb_Active_Cfg;         
            Transfer_Cnt = 1;                            
            Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
            break;
 
            
        case SET_CFG:           // 9
            USB_StdSetCfg_Handler();
            break;
            
         
        case GET_INTF:			/* 11 Notice when the Setup_Pkt.bIntfId > 1*/
           if(Setup_Pkt.CtlIntf.bIntfID < MAX_NUM_INTF)
           {
              pSrc = (byte*)&Usb_Alt_Intf + Setup_Pkt.CtlIntf.bIntfID;  
              Transfer_Cnt = 1;                            
              Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
           }
           /*
           else
            {
              //add code for more than 1 interface, notice the value of  MAX_NUM_INTF
            }
           */
           break;
            
        case SET_INTF:
            Usb_Alt_Intf[Setup_Pkt.CtlIntf.bIntfID] = Setup_Pkt.CtlIntf.bAltID;
            Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
            break;
            
//        case SET_DSC:
//        case SYNCH_FRAME:
        default:
            break;
    }
    
  return;  
}

/******************************************************************************
 * Function:        void USB_ClassReq_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        The routine will be called when the request in setup packet 
 *                  can not be parsed. It will call the routines in Std_Class_Req_Handler,
 *                  The new routine for new class can be added to this array when 
 *                  a new standard class is required. The user can also add its owner 
 *                  processing for customize protocol.  
 * Note:            None
 *****************************************************************************/
void USB_ClassReq_Handler(void)
{
    byte i;
     
    for(i=0;i < (sizeof(Class_Req_Handler)/sizeof(pFunc)); i++)
     {
       if(Ctrl_Trf_Session_Owner != CLASS_NULL)  /*if the request has been parsed, return*/
         return;
            
       if(Class_Req_Handler[i])              /*if the routine is valid, then call*/
         Class_Req_Handler[i]();             
    }
    
    return;
}

/******************************************************************************
 * Function:        void USB_StdGetDsc_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function handles the standard GET_DESCRIPTOR request.
 *****************************************************************************/
void USB_StdGetDsc_Handler(void)
{
    if(Setup_Pkt.StdCtl.bmRequestType == 0x80)
    {
        switch(Setup_Pkt.ReqWval.bDscType)
        {
            case DSC_DEV:
                Transfer_Cnt = sizeof(Device_Dsc);
                pSrc = (byte*)&Device_Dsc;
                Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
                break;
                
            case DSC_CFG:
                Transfer_Cnt = sizeof(USB_CFG);            
                pSrc = &Cfg_01;
                Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
                break;
                
            case DSC_STR:
                  pSrc = (unsigned char *)&sd000;
                  if (Setup_Pkt.ReqWval.bDscIndex==2){
                    pSrc = (unsigned char *)&sd002;
                  } 

           	    Transfer_Cnt = *pSrc;                 
                Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
                break;
                
            default:
            break;
        }
        
    }
    
  return;
}

/******************************************************************************
 * Function:        void USB_StdSetCfg_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function disables all endpoints except 0 by clearing
 *                  EPCTL registers, then initializes these endpoints
 *
 * Note:            None
 *****************************************************************************/
void USB_StdSetCfg_Handler(void)
{
    Clear_Mem((byte*)&EPCTL1,6);                          
    Clear_Mem((byte*)&Usb_Alt_Intf,MAX_NUM_INTF);

    Usb_Active_Cfg = Setup_Pkt.CtrCfg.bCfgValue;
    
    Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;
    
    if(Setup_Pkt.CtrCfg.bCfgValue == 0)
        Usb_Device_State = ADDRESS_STATE;
    else
    {
        Usb_Device_State = CONFIGURED_STATE;

        Init_EP_For_HID();                    /*it can also be placed to the USB initialization routine*/
    }
    
    return;
}

/******************************************************************************
 * Function:        void USB_StdGetStatus_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function handles the standard GET_STATUS request
 * Note:            None
 *****************************************************************************/
void USB_StdGetStatus_Handler(void)
{
    CtrlTrf_Data.EachByte._byte0 = 0;                         
    CtrlTrf_Data.EachByte._byte1 = 0;
        
    if (Setup_Pkt.CtlReqT.Recipient == RCPT_DEV){
              /* _byte0: bit0: Self-Powered Status [0] Bus-Powered [1] Self-Powered  */
             /*         bit1: RemoteWakeup        [0] Disabled    [1] Enabled       */
             
      if(Usb_Stat.BitCtl.Self_Power)
        CtrlTrf_Data.EachByte._byte0|=0b000000001;   
                       
      if(Usb_Stat.BitCtl.RemoteWakeup == 1)         
        CtrlTrf_Data.EachByte._byte0|=0b00000010;     
            
      Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;             
    } 
    
    else if (Setup_Pkt.CtlReqT.Recipient == RCPT_INTF){
      Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;     
    } 
    
    else if (Setup_Pkt.CtlReqT.Recipient == RCPT_EP){
 //     if((Setup_Pkt.EpND.EPNum == 0b0001 ) && (Setup_Pkt.EpND.EPDir)){
     
        if(Bdtmap.ep1Bio.Stat.McuCtlBit.BDTSTALL) 
          CtrlTrf_Data.EachByte._byte0 |= 0x01;
              
        Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;  
//      }
    }
    
    if(Ctrl_Trf_Session_Owner == STANDARD_CLASS_ID)
    {
        Transfer_Cnt = 2;  
        pSrc = (byte*)&CtrlTrf_Data;           
                                 
    }
   

}

/******************************************************************************
 * Function:        void USB_StdFeatureReq_Handler(void)
 * Input:           None
 * Output:          None
 * Overview:        This function dealt with the standard SET & CLEAR FEATURES
 *                  requests
 * Note:            None
 *****************************************************************************/
void USB_StdFeatureReq_Handler(void)
{
    Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID;          

    if((Setup_Pkt.CtlReqT.bFeature == DEVICE_REMOTE_WAKEUP)&&
       (Setup_Pkt.CtlReqT.Recipient == RCPT_DEV))
    {
        if(Setup_Pkt.StdCtl.bRequest == SET_FEATURE)
            Usb_Stat.BitCtl.RemoteWakeup = 1;
        else
            Usb_Stat.BitCtl.RemoteWakeup = 0;
        
//        Ctrl_Trf_Session_Owner = STANDARD_CLASS_ID; 
    }
    
    if((Setup_Pkt.CtlReqT.bFeature == ENDPOINT_HALT)&&
       (Setup_Pkt.CtlReqT.Recipient == RCPT_EP)&&
       (Setup_Pkt.EpND.EPNum != 0))
    {
//       if(Setup_Pkt.EpND.EPNum == 0b0001)
//       {
         if(Setup_Pkt.StdCtl.bRequest == SET_FEATURE){
            if(Setup_Pkt.EpND.EPDir){              // IN endpoint
              Bdtmap.ep1Bio.Stat.McuCtlBit.BDTSTALL = 1;
            } 
            else {
  //            Bdtmap.ep2Bio.Stat.McuCtlBit.BDTSTALL = 1;
            }
            
          }
          else{            // clear_feature
          
            if(Setup_Pkt.EpND.EPDir){              // IN endpoint
            
              Bdtmap.ep1Bio.Stat.McuCtlBit.BDTSTALL = 0;
            } 
              
            
          
       }

    }
    
  return;
}

