#include "def.h"
#include "val.h"
#include "mcu.h"
#include "dfu.h"
#include "spk.h"
#include "wm8987l.h"
#include "usbcode.h"
#include "usb.h"


//-----MCU.C-----//
extern void Delay_Xms( BYTE );
extern void Reboot_Mcu( BYTE );

//-----DFU.C-----//
extern idata DFU Dfu;
extern void DFU_Read( void );
extern void DFU_Write( BYTE );

//-----SPK.C-----//
extern idata SPK Spk;
extern void SPK_Reset( void );
extern BIT SPK_Status( void );
extern void SPK_PLL_Divider( void );
extern void SPK_VOL_Vol_Ctrl( BYTE , BYTE );
extern void SPK_VOL_Mix_Ctrl( BYTE );
extern void SPK_VOL_Mic_Ctrl( BYTE );

//-----WM8987L.C-----//
extern WOLFSON Wm8987l;
extern void Wm8987l_Power_Up( void );
extern void Wm8987l_Power_Down( void );
extern void Wm8987l_Bass( BYTE Vol );
extern void Wm8987l_Treble( BYTE Vol );


EP0INFO Ep0;



void Initial_USB( void )
  { USB[IEN] = CLR;                              // Disable USB all related interrupts
    
    USB[EPINDEX] = EP0;                          // Change to EP0 
    USB[EPCON] = ( TXEPEN | RXEPEN );            // Enable Tx & Rx
    USB[EPCON] |= ( TXSTL | RXSTL );             // Set RXSTL & TXSTL (prevent not SETUP Token)
    USB[TXCON] = TXCLR;                          // Clear Tx FIFO
    USB[RXCON] = RXCLR;                          // Clear Rx FIFO
        
//    USB[SFMCTL] |= PLL_LOCK_USB;                 // PLL lock to 1ms interval time on USB SOF
                                                 // and Divide value = 1
    USB[PFTH] |= BFA;                            // Enable 576 bytes Buffer for Audio function
    
    
#ifdef SI_IIS                                    // Serial Interface
    USB[SIFCFG] &= ~PCMI_EN;
  #ifdef IIS_STD                                 // Standar IIS
    USB[SIFCFG] &= ~DFSYC;
  #endif
  #ifdef IIS_LJF                                 // Left Justified
    USB[SIFCFG] |= DFSYC;
  #endif
#endif

#ifdef SI_PCM                                    // Serial Interface
    USB[SIFCFG] |= PCMI_EN;
  #ifdef PCM_SSY                                 // Short Sync
    USB[SIFCFG] &= ~DFSYC;
  #endif
  #ifdef PCM_LSY                                 // Long Sync
    USB[SIFCFG] |= DFSYC;
  #endif
#endif

#ifdef SI_SD16                                   // Serial Interface - Data Length
    USB[SIFCFG] |= SD16EN;
#endif
#ifdef SI_SD32                                   // Serial Interface - Data Length
    USB[SIFCFG] &= ~SD16EN;
#endif


#ifdef SD_PCM16
    USB[SDFCFG] &= ~PCM8EN;
#endif
#ifdef SD_PCM8
    USB[SDFCFG] |= PCM8EN;
#endif

#ifdef SD_MI
    USB[SDFCFG] &= ~AISTERO;
#endif
#ifdef SD_SI
    USB[SDFCFG] |= AISTERO;
#endif

#ifdef SD_MO
    USB[SDFCFG] |= AOMON;
#endif
#ifdef SD_SO
    USB[SDFCFG] &= ~AOMON;
#endif

#ifdef SF_48K
    USB[SDFCFG] |= ASRS2;
    USB[SDFCFG] |= ASRS1;
    USB[SDFCFG] |= ASRS0;
#endif
#ifdef SF_32K
    USB[SDFCFG] &= ~ASRS2;
    USB[SDFCFG] |= ASRS1;
    USB[SDFCFG] |= ASRS0;
#endif
#ifdef SF_24K
    USB[SDFCFG] |= ASRS2;
    USB[SDFCFG] |= ASRS1;
    USB[SDFCFG] &= ~ASRS0;
#endif
#ifdef SF_16K
    USB[SDFCFG] &= ~ASRS2;
    USB[SDFCFG] |= ASRS1;
    USB[SDFCFG] &= ~ASRS0;
#endif
#ifdef SF_12K
    USB[SDFCFG] |= ASRS2;
    USB[SDFCFG] &= ~ASRS1;
    USB[SDFCFG] |= ASRS0;
#endif
#ifdef SF_8K
    USB[SDFCFG] &= ~ASRS2;
    USB[SDFCFG] &= ~ASRS1;
    USB[SDFCFG] |= ASRS0;
#endif
#ifdef SF_44_1K
    USB[SDFCFG] |= ASRS2;
    USB[SDFCFG] &= ~ASRS1;
    USB[SDFCFG] &= ~ASRS0;
#endif
#ifdef SF_22_05K
    USB[SDFCFG] &= ~ASRS2;
    USB[SDFCFG] &= ~ASRS1;
    USB[SDFCFG] &= ~ASRS0;
#endif
                                                 // Enable SIF0 Interface ( H/W pin will be Output )
    USB[SIOCTL] |= ( SIFOE | MCKFD | MCKOE1 | MCKOE0 );
                                                 // 12.288 Mhz
    USB[AFCTL] |= ( AOFEN | MIXEN | AIFEN );     // 
#ifdef PM_LBP
    USB[AFCTL] |= LPBEN;
#endif
    
    USB[UIE] = ( UTXIE0 | URXIE0 | UTXIE1  | SOFIE | ASOFIE );
    
    USB[IEN] = ( EF | EFSR );                    // Enable USB all related interrupts
    
    Ep0.Unit = DFU_MAX;                          // 
    Ep0.EmuOk = CLR;                             // Check Emulation status
    Ep0.RWEN = CLR;                              // Remote/Wakeup flag ( Default " Disable " )
    
    Ep0.Out_AltSet = SPKALTSET0;
    Ep0.In_AltSet = SPKALTSET0;
    
    USB[UPCON] |= CONEN;                         // Connecter to Host ( Enable the pull-up resistor )
  }


void USB_Rd_FIFO( BYTE *Buffer , BYTE Cnt )
  { BYTE i;
    
    
    for ( i=0 ; i<Cnt ; i++ )  
       Buffer[i] = USB[RXDAT];
  }


void USB_Wr_FIFO( BYTE *Buffer , BYTE Cnt )
  { BYTE i;
    
    
    for ( i=0 ; i<Cnt ; i++ )  
       USB[TXDAT] = Buffer[i];
  }


void USB_Ep0_FIFO( void )
  { BYTE BLen;
    
    
    USB[TXCON] = TXCLR;                          // Clear Tx FIFO
    
    if ( USB[RXSTAT] & ( STOVW | EDOVW ))        // Setup Token
      { Ep0.Stage = SETUPSTAGE;
        while(1)
          { while(USB[RXSTAT] & STOVW);          // waiting STOVE = 0
            while(!( USB[RXSTAT] & EDOVW ));     // waiting EDOVW = 1
            USB[RXSTAT] &= ~EDOVW;               // Clear the EDOVW bit when reading the contents of the FIFO
            USB[UIFLG] = URXD0;                  // Write "1" to Clear this Flag
            BLen = USB[RXCNT];                   // Chk total Rx Data count in Byte
            USB_Rd_FIFO( Ep0.RxTx , BLen );
            if (!(USB[RXSTAT] & ( STOVW | EDOVW )))
              break;
          }
        USB[EPCON] &= ~( RXSTL | TXSTL );        // Release Rx/Tx STAL
        USB[RXSTAT] &= ~RXSETUP;                 // Release Setup Token flag
        Ep0.All = BLen;                          // Only for analytic "Urd"
      }
    else if ( Ep0.Stage == DFU_WR_STAGE )
      { BLen = USB[RXCNT];                       // Chk total Rx Data count in Byte  
      	Ep0.All -= BLen;
      	
      	USB_Rd_FIFO( Ep0.RxTx , BLen );
      	DFU_Write( BLen );
        
        if ( Ep0.All == 0 )
          { USB[TXCNT] = 0;
            Ep0.Stage = STATUSSTAGE;
          }
      }
    else if ( Ep0.Stage == USBSPKSTAGE )
      { BLen = USB[RXCNT];                       // Chk total Rx Data count in Byte  
      	USB_Rd_FIFO( Ep0.RxTx , BLen );
        if ( Spk.CS == SPK_CS_MUTE )
          { if ( Ep0.RxTx[0] == 0x01 )
              { if ( Spk.IDS == ID_SPK_FU )
              	  { Spk.Vol_Mute = SET;
              	  
                    SPK_VOL_Vol_Ctrl( Spk.Silente , Spk.Silente );
                    
                    USB[AFCTL] |= ADO_ME;
                    
//                    if ( Spk.Mix_Mute == CLR )
//                      { SPK_VOL_Mix_Ctrl( Spk.Silente );
//                        USB[AFCTL] &= ~MIXEN;    // Signel Chip tape out should be modify
//                      }
                  }
                else if ( Spk.IDS == ID_MIC_FU )
                  { Spk.Mic_Mute = SET;
                    
                    SPK_VOL_Mic_Ctrl( Spk.Silente );
                    
                    USB[AFCTL] |= ADI_ME;
                  }
                else if ( Spk.IDS == ID_MIX_FU )
                  { Spk.Mix_Mute = SET;
                    
                    SPK_VOL_Mix_Ctrl( Spk.Silente );
                    
                    USB[AFCTL] &= ~MIXEN;
                    
//                    if ( Spk.Vol_Mute == CLR )
//                      { SPK_VOL_Mix_Ctrl( Spk.Silente );
//                        USB[AFCTL] &= ~MIXEN;    // Signel Chip tape out should be modify
//                      }
                  }
              }
            else
              { if ( Spk.IDS == ID_SPK_FU )
              	  { Spk.Vol_Mute = CLR;
              	    
              	    USB[AFCTL] &= ~ADO_ME;
              	    
              	    SPK_VOL_Vol_Ctrl( Spk.LCurVol , Spk.RCurVol );
              	    
//                    if ( Spk.Mix_Mute == CLR )
//                      { USB[AFCTL] |= MIXEN;     // Signel Chip tape out should be modify
//                        SPK_VOL_Mix_Ctrl( Spk.Mix_Cur );
//                      }
                  }
                else if ( Spk.IDS == ID_MIC_FU )
                  { Spk.Mic_Mute = CLR;
                    
                    USB[AFCTL] &= ~ADI_ME;
                    
                    SPK_VOL_Mic_Ctrl( Spk.Mic_Cur );
                  }
                else if ( Spk.IDS == ID_MIX_FU )
                  { Spk.Mix_Mute = CLR;
                  
                    USB[AFCTL] |= MIXEN;
                    
                    SPK_VOL_Mix_Ctrl( Spk.Mix_Cur );
                    
//                    if ( Spk.Vol_Mute == CLR )
//                      { USB[AFCTL] |= MIXEN;     // Signel Chip tape out should be modify
//                        SPK_VOL_Mix_Ctrl( Spk.Mix_Cur );
//                      }
                  }
              }
          }
        else if ( Spk.CS == SPK_CS_VOLUME )
          { if ( Spk.Channel == SPK_M_CHANNEL )
      	      { if ( Ep0.RxTx[1] == 0x80 )       // Silence
      	          { if ( Spk.IDS == ID_MIC_FU )
                      Spk.Mic_Cur = Spk.Silente;
                    else if ( Spk.IDS == ID_MIX_FU )
                      Spk.Mix_Cur = Spk.Silente;
                    else
                      { Spk.Vol_Cur = Spk.Silente;
      	                Spk.LCurVol = Spk.Silente;
                        Spk.RCurVol = Spk.Silente;
                      }
      	          }
      	        else
      	          { if ( Spk.IDS == ID_MIC_FU )
                      Spk.Mic_Cur = (signed char)(Ep0.RxTx[1]);
                    else if ( Spk.IDS == ID_MIX_FU )
                      Spk.Mix_Cur = (signed char)(Ep0.RxTx[1]);
                    else
                      { Spk.Vol_Cur = (signed char)(Ep0.RxTx[1]);
      	                Spk.LCurVol = (signed char)(Ep0.RxTx[1]);
                        Spk.RCurVol = (signed char)(Ep0.RxTx[1]);
                      }
      	          }
      	      }
      	    else                                 // Only for Speaker
      	      { if ( Ep0.RxTx[1] == 0x80 )       // Silence
                  { if ( Spk.Channel == SPK_L_CHANNEL )
      	              Spk.LCurVol = Spk.Silente;
      	            else
      	              Spk.RCurVol = Spk.Silente;
      	          }
                else
      	          { if ( Spk.Channel == SPK_L_CHANNEL )
      	              Spk.LCurVol = (signed char)(Ep0.RxTx[1]);
      	            else
      	              Spk.RCurVol = (signed char)(Ep0.RxTx[1]);
      	          }
      	      }
      	      
      	    if ( Spk.IDS == ID_SPK_FU )
      	      SPK_VOL_Vol_Ctrl( Spk.LCurVol , Spk.RCurVol );
            else if ( Spk.IDS == ID_MIC_FU )
              SPK_VOL_Mic_Ctrl( Spk.Mic_Cur );
            else if ( Spk.IDS == ID_MIX_FU )
              SPK_VOL_Mix_Ctrl( Spk.Mix_Cur );

            Spk.Channel = SPK_X_CHANNEL;         // Unknow Channel
          }
        else if ( Spk.CS == SPK_CS_BASS )
          { Wm8987l_Bass( Ep0.RxTx[0] );
            Spk.Bas_Cur = Ep0.RxTx[0];
          }
      	else if ( Spk.CS == SPK_CS_TREBLE )
      	  { Wm8987l_Treble( Ep0.RxTx[0] );
            Spk.Trb_Cur = Ep0.RxTx[0];
      	  }
        else if ( Spk.CS == SPK_CS_FEQ )         // 
          { 
          }
        
      	Ep0.All = 0;
        USB[TXCNT] = 0;
        Ep0.Stage = STATUSSTAGE;
      }
    else                                         // Zero Length Data in RXCNT
      { Ep0.Stage = STATUSSTAGE;
      	USB[EPCON] |= ( RXSTL | TXSTL );         // Receive the host "ACK" transaction , we should set Rx/Tx STAL
      }
    
    USB[RXCON] |= RXFFRC;                        // Set this bit , meaning that Rx Data has Read Complete
  }
  

void USB_Get_Status( void )
  { Ep0.All = 2;                                 // Only 2 byte transfer to the host
    
    
    Ep0.RxTx[1] = 0;
    switch( Ep0.RxTx[0] & 0x03 )                 // Request Type ( Reserve low 2 bit )
      { case DEVICEREQUEST:    if ( Ep0.RWEN )
                                 Ep0.RxTx[0] = 0x02;// Return Function Remove Wake-up Enable
                               else
                                 Ep0.RxTx[0] = 0x00;// Return Function Remove Wake-up Disable
#ifdef SELF_POWER                                // Report Self Power
                               Ep0.RxTx[0] |= 0x01;
#endif
                               break;            // Chk Remote wakeup enabled or not
        case ENDPOINTREQUEST:  USB[EPINDEX] = Ep0.RxTx[4] & 0x0F;
                               if (( USB[EPCON] & RXSTL )||( USB[EPCON] & TXSTL ))
                                 Ep0.RxTx[0] = 0x01;// if EndPoint Rx/Tx STAL then set EndPoint Halt
                               else
                                 Ep0.RxTx[0] = 0x00;// else seting this EndPoint Avaliable for Rx/Tx  
                               USB[EPINDEX] = EP0;
                               break;
        case INTERFACEREQUEST: break;
        default:               USB[EPCON] |= ( RXSTL | TXSTL );
                               break; 
      }
  }  	


void USB_Clear_Feature( void )
  { switch( Ep0.RxTx[0] & 0x03 )                 // Request Type ( Reserve low 2 bit )
      { case DEVICEREQUEST:    if ( Ep0.RxTx[2] == DEVICE_REMOTE_WAKEUP )
                                 Ep0.RWEN = CLR;
                               else
                                 USB[EPCON] |= ( RXSTL | TXSTL );
                               break;            // Disable the Device Remote Wakeup function
        case ENDPOINTREQUEST:  if ( Ep0.RxTx[2] == ENDPOINT_HALT )
                                 { USB[EPINDEX] = Ep0.RxTx[4] & 0x0F;
                                   USB[EPCON] &= ~( RXSTL | TXSTL );
                                   USB[RXSTAT] = RXSOVW;// Enable RXSEQ/TXSEQ bit can be Updata , and
                                   USB[TXSTAT] = TXSOVW;// set Rx/Tx toggle buffer into DATA0
                                   USB[EPINDEX] = EP0;
                                 }
                               else
                                 USB[EPCON] |= ( RXSTL | TXSTL );
                               break;
        case INTERFACEREQUEST: break;
        default:               USB[EPCON] |= ( RXSTL | TXSTL );
                               break;
      }
  }
 
  
void USB_Set_Feature( void )
  { switch( Ep0.RxTx[0] & 0x03 )                 // Request Type ( Reserve low 2 bit )
      { case DEVICEREQUEST:    if ( Ep0.RxTx[2] == DEVICE_REMOTE_WAKEUP )
                                 Ep0.RWEN = SET;
                               else
                                 USB[EPCON] |= ( RXSTL | TXSTL );
                               break;            // Disable the Device Remote Wakeup function
        case ENDPOINTREQUEST:  if ( Ep0.RxTx[2] == ENDPOINT_HALT )
                                 { USB[EPINDEX] = Ep0.RxTx[4] & 0x0F;
                                   USB[EPCON] |= ( RXSTL | TXSTL );
                                   USB[EPINDEX] = EP0;
                                 }
                               else
                                 USB[EPCON] |= ( RXSTL | TXSTL );
                               break;
        case INTERFACEREQUEST: break;
        default:               USB[EPCON] |= ( RXSTL | TXSTL );
                               break; 
      }
  }  


void USB_Get_Descriptor( void )
  { union WTYPE WLen;
    
    
    WLen.B[0] = 0x00;                            // MSB
    Ep0.DWLen.B[0] = Ep0.RxTx[7];                // MSB
    Ep0.DWLen.B[1] = Ep0.RxTx[6];                // LSB
    switch( Ep0.RxTx[3] )	
      { case DEVICEDESCRIPTOR:        Ep0.Buf = DEVICE_DESCRIPTOR;
                                      WLen.B[1] = Ep0.Buf[0];
                                      break;
        case CONFIGURATIONDESCRIPTOR: Ep0.Buf = CONGFIGURATION_DESCRIPTOR;
                                      WLen.B[1] = Ep0.Buf[2];// LSB
                                      break;
        case STRINGDESCRIPTOR:        switch( Ep0.RxTx[2] )
                                        { case 0:  Ep0.Buf = LANGUAGEID_DESCRIPTOR;
                                                   break;
                                          case 1:  if ( DEVICE_DESCRIPTOR[14] )
                                                     Ep0.Buf = MANUFACTURER_DESCRIPTOR;
                                                   else
                                                     USB[EPCON] |= ( RXSTL | TXSTL );
                                                   break;
                                          case 2:  if ( DEVICE_DESCRIPTOR[15] )
                                                     Ep0.Buf = PRODUCT_DESCRIPTOR;
                                                   else
                                                     USB[EPCON] |= ( RXSTL | TXSTL );
                                                   break;
                                          default: USB[EPCON] |= ( RXSTL | TXSTL );
                                                   break;
                                        }
                                      WLen.B[1] = Ep0.Buf[0];
                                      break;
      	case HIDDESCRIPTOR:           Ep0.Buf = HID_DESCRIPTOR;
                                      WLen.B[1] = Ep0.Buf[0];
                                      break;
      	case HIDREPORT:               Ep0.Buf = HID_REPORT;
      	                              WLen.B[1] = HID_DESCRIPTOR[7];
      	                              break;
      	default:                      USB[EPCON] |= ( RXSTL | TXSTL );
                                      break;
      }
    
    if ( Ep0.DWLen.W[0] > WLen.W )
      Ep0.All = WLen.W;
    else
      Ep0.All = Ep0.DWLen.W[0];
    
  }


void USB_Set_Configuration( void )
  { BYTE i;
    
    
    Ep0.Tmp = Ep0.RxTx[2];
    if ( Ep0.Tmp )
      { 
#ifdef PM_LBP      	
      	for ( i=1 ; i<3 ; i++ )
#endif
#ifdef PM_DTP
      	for ( i=1 ; i<6 ; i++ )
#endif
           { USB[EPINDEX] = i;
             USB[EPCON] = 0x0F;                  // Enable Receive Input/Transmit Output
             USB[RXCON] = RXCLR;                 // Clear Rx FIFO
             USB[TXCON] = TXCLR;                 // Clear Tx FIFO
             USB[RXSTAT] = RXSOVW;               // Enable RXSEQ/TXSEQ bit can be Updata , and
             USB[TXSTAT] = TXSOVW;               // set Rx/Tx toggle buffer into DATA0
           }
        
        Ep0.EmuOk = SET;                         // Emulation Flow pass
        USBLED = CLR;                            // USB LED ON , USB initial OK.
        
        USB[GS_LCO] = 0x12;                      // -10dB
        USB[GS_RCO] = 0x12;
        USB[GS_ADI] = 0x12;
        USB[GS_MIX] = 0x12;
        
        Spk.Vol_Max = 0x17;                      // 0dB
        Spk.Vol_Min = 0x01;                      // -48dB
        Spk.Silente = 0x00;                      // -54dB
        Spk.Vol_Cur = 0x12;                      // -10dB
        
        Spk.Mic_Max = 0x17;
        Spk.Mic_Cur = 0x12;
        
        Spk.Mix_Max = 0x17;
        Spk.Mix_Cur = 0x12;
        
        Spk.Bas_Cur = 0;                         // Current Bass(0x00)
        Spk.Bas_Max = 15;                        // (0x0F)
        Spk.Bas_Min = 0;                         // 
        Spk.Trb_Cur = 0;                         // Current Treble(0x00)
        Spk.Trb_Max = 15;                        // (0x0C)
        Spk.Trb_Min = 0;                         //
        
        Spk.LCurVol = Spk.Vol_Cur;
        Spk.RCurVol = Spk.Vol_Cur;
        Spk.Channel = SPK_X_CHANNEL;             // Unknow Channel
    
        Spk.Tmp = 0xFF;                          // Initial for Volume Index
        
        USB[AFCTL] |=  SIFEN;                    // Enable Serial Interface
      }
    else                                         // Set EP1,2,3,4 into Address state
      { for ( i=1 ; i<6 ; i++ )
           { USB[EPINDEX] = i;
             USB[EPCON] = 0x00;
           }
        
        USBLED = SET;                            // USB LED OFF , USB initial Fail.
        Ep0.Out_AltSet = SPKALTSET0;
        
        USB[AFCTL] &= ~SIFEN;                    // Disable Serial Interface
        
      }
    USB[EPINDEX] = EP0;
  }


void USB_Set_Interface( void )
  { switch( Ep0.RxTx[4] )
      { case 0:                                  // For Interface0 ( HID )
        case 1:  if ( Ep0.RxTx[2] > 0 )          // For Interface1 ( Audio Control )
                   USB[EPCON] |= ( RXSTL | TXSTL );
                 else
                   USB[TXCNT] = 0;
                 break;
        case 2:  if ( Ep0.RxTx[2] > 1 )          // Audio Out
                   USB[EPCON] |= ( RXSTL | TXSTL );
                 else  
                   { Ep0.Out_AltSet = Ep0.RxTx[2];
                     USB[TXCNT] = 0;
                   }
                 break;
        case 3:  if ( Ep0.RxTx[2] > 1 )          // Audio In
                   USB[EPCON] |= ( RXSTL | TXSTL );
                 else  
                   { Ep0.In_AltSet = Ep0.RxTx[2];
                     USB[TXCNT] = 0;
                   }
                 break;
        default: USB[EPCON] |= ( RXSTL | TXSTL );
                 break;
      }
  }


void USB_Get_Interface( void )
  { Ep0.All = 1;
    switch( Ep0.RxTx[4] )
      { case 0:                                  // For Interface0 ( HID )
        case 1:  Ep0.RxTx[0] = 0;                // For Interface1 ( Audio Control )
                 break;
        case 2:  Ep0.RxTx[0] = Ep0.Out_AltSet;
                 break;
        case 3:  Ep0.RxTx[0] = Ep0.In_AltSet;
                 break;
        default: USB[EPCON] |= ( RXSTL | TXSTL );
                 break;
      }
  }


void USB_CtrlRd( void )                          // Host In , USB Out ( Only for EP0 )
  { BYTE BLen;
    
    
    if ( Ep0.Stage == DATASTAGE )                // In DATASTAGE we should move Data to TXFIFO
      { if ( Ep0.All > Ep0.Unit )
          BLen = Ep0.Unit;
        else
          BLen = Ep0.All;
      	USB_Wr_FIFO( Ep0.Buf , BLen );
      	USB[TXCNT] = BLen;                       // Set this byte will Trigger USB to Transmit Data to the Host
        Ep0.All -= BLen;                         // Calculated the Remain Data size
        Ep0.Buf += BLen;                         // Move Buffer Address in Right position
      }
    else if ( Ep0.Stage == DFU_RD_STAGE )
      { if ( Ep0.All > Ep0.Unit )
          BLen = Ep0.Unit;
        else
          BLen = Ep0.All;
      	
      	if ( BLen == DFU_MAX )
      	  DFU_Read();
      	
      	USB_Wr_FIFO( Ep0.RxTx , BLen );
      	
      	USB[TXCNT] = BLen;                       // Set this byte will Trigger USB to Transmit Data to the Host
        Ep0.All -= BLen;                         // Calculated the Remain Data size
      }
    else if ( Ep0.Stage == USBSPKSTAGE )
      { if ( Spk.CS == SPK_CS_MUTE )
          { if ( Spk.IDS == ID_SPK_FU )
              Ep0.RxTx[0] = Spk.Vol_Mute;
            else if ( Spk.IDS == ID_MIX_FU )
              Ep0.RxTx[0] = Spk.Mix_Mute;
            else if ( Spk.IDS == ID_MIC_FU )
              Ep0.RxTx[0] = Spk.Mic_Mute;
          }
        else if ( Spk.CS == SPK_CS_VOLUME )
          { Ep0.RxTx[0] = 0x00;// LSB
            if ( Ep0.RxTx[1] == GET_SPK_MAX )
              { if ( Spk.IDS == ID_MIC_FU )
                  Ep0.RxTx[1] = Spk.Mic_Max;
                else if ( Spk.IDS == ID_MIX_FU )
                  Ep0.RxTx[1] = Spk.Mix_Max;
                else if ( Spk.IDS == ID_SPK_FU )
                  Ep0.RxTx[1] = Spk.Vol_Max;
                else
                  { USB[EPCON] |= ( RXSTL | TXSTL );
                    return;
                  }
              }
            else if ( Ep0.RxTx[1] == GET_SPK_MIN )
              Ep0.RxTx[1] = Spk.Vol_Min;
            else if ( Ep0.RxTx[1] == GET_SPK_CUR )
              { if ( Spk.IDS == ID_MIC_FU )
                  Ep0.RxTx[1] = Spk.Mic_Cur;
                else if ( Spk.IDS == ID_MIX_FU )
                  Ep0.RxTx[1] = Spk.Mix_Cur;
                else if ( Spk.IDS == ID_SPK_FU )
                  Ep0.RxTx[1] = Spk.Vol_Cur;
                else
                  { USB[EPCON] |= ( RXSTL | TXSTL );
                    return;
                  }
              }
            else if ( Ep0.RxTx[1] == GET_SPK_RES )
              Ep0.RxTx[1] = 0x01;
          }
        else if ( Spk.CS == SPK_CS_BASS )
          { if ( Ep0.RxTx[1] == GET_SPK_MAX )
              Ep0.RxTx[0] = Spk.Bas_Max;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_MIN )
              Ep0.RxTx[0] = Spk.Bas_Min;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_CUR )
              Ep0.RxTx[0] = Spk.Bas_Cur;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_RES )
              Ep0.RxTx[0] = 0x01;// MSB
          }
        else if ( Spk.CS == SPK_CS_TREBLE )
          { if ( Ep0.RxTx[1] == GET_SPK_MAX )
              Ep0.RxTx[0] = Spk.Trb_Max;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_MIN )
              Ep0.RxTx[0] = Spk.Trb_Min;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_CUR )
              Ep0.RxTx[0] = Spk.Trb_Cur;// MSB
            else if ( Ep0.RxTx[1] == GET_SPK_RES )
              Ep0.RxTx[0] = 0x01;// MSB
          }
        else if (  Spk.CS == SPK_CS_UNDEFINED )
          { if ( Spk.IDS == ID_SU )
              Ep0.RxTx[0] = 0x01;
            else
              { USB[EPCON] |= ( RXSTL | TXSTL );
                return;
              }
          }
        else
          { USB[EPCON] |= ( RXSTL | TXSTL );
            return;
          }
        
        if ( Ep0.All > Ep0.Unit )
          BLen = Ep0.Unit;
        else
          BLen = Ep0.All;
      	USB_Wr_FIFO( Ep0.Buf , BLen );
      	USB[TXCNT] = BLen;                       // Set this byte will Trigger USB to Transmit Data to the Host
        Ep0.All -= BLen;                         // Calculated the Remain Data size
        Ep0.Buf += BLen;                         // Move Buffer Address in Right position
      }
    else
      { USB[EPCON] |= ( RXSTL | TXSTL );         // In STATUSSTAGE we should STAL Rx/Tx
        if ( Ep0.Stage == SETADDRESS )           // Different from other STATUSSTAGE(importent)
          { USB[UADDR] = Ep0.Tmp;                // Set Address
//            USB[SFMCTL] = ( Spk.HfCon | PLL_LOCK_USB );
            USB[SFMCTL] = 0x33;
          }
        if ( Dfu.Stage == DFU_RESET )
          { Reboot_Mcu( REBOOT_TO_ISP );
          }
      }
  }


void USB_Stardard_Request( void )
  { switch( Ep0.RxTx[1] )                        // Request Code
      { case GET_STATUS:        Ep0.Stage = DATASTAGE;
                                USB_Get_Status();
                                USB_CtrlRd();
                                break;
        case CLEAR_FRATURE:	Ep0.Stage = STATUSSTAGE;  
                                USB_Clear_Feature();
                                USB[TXCNT] = 0;  // USB will return ACK immediately when receive IN transaction
                                break;
        case SET_FEATURE:       Ep0.Stage = STATUSSTAGE;
                                USB_Set_Feature();
                                USB[TXCNT] = 0;  // USB will return ACK immediately when receive IN transaction  
                                break;
        case SET_ADDRESS:       Ep0.Stage = SETADDRESS;// Different from other STATUSSTAGE
                                Ep0.Tmp = Ep0.RxTx[2];
                                USB[TXCNT] = 0;  // USB will return ACK immediately when receive IN transaction  
                                break;
        case GET_DESCRIPTOR:    Ep0.Stage = DATASTAGE;
                                USB_Get_Descriptor();
                                USB_CtrlRd();
                                break;
//        case SET_DESCRIPTOR:    break;
        case GET_CONFIGURATION: Ep0.Stage = DATASTAGE;
                                Ep0.RxTx[0] = Ep0.Tmp;// This value get from SET_CONFIGURATION transaction
                                Ep0.All = 1;     // Only 1 byte transfer to the host
                                USB_CtrlRd();
                                break;
        case SET_CONFIGURATION: Ep0.Stage = STATUSSTAGE;
                                USB_Set_Configuration(); // Will store configuration value to Ep0.Tmp
                                USB[TXCNT] = 0;  // USB will return ACK immediately when receive IN transaction
                                break;
        case SET_INTERFACE:     Ep0.Stage = STATUSSTAGE;
                                USB_Set_Interface();
                                break;
        case GET_INTERFACE:     Ep0.Stage = DATASTAGE;
                                USB_Get_Interface();
                                USB_CtrlRd();
                                break;
        case SYNCH_FRAME:       Ep0.Stage = STATUSSTAGE;
                                USB[TXCNT] = 0;  // USB will return ACK immediately when receive IN transaction
                                Ep0.All = 0;
                                break;
        default:                USB[EPCON] |= ( RXSTL | TXSTL );
                                break;           // Set Rx/Tx STAL 
      }
  }


void USB_Class_Request( void )
  { if ( Ep0.RxTx[0] & GET_REQUEST )             // Get Request
      { switch( Ep0.RxTx[1] )                    // Request Code
          { case GET_IDLE:     Ep0.Stage = DATASTAGE;
                               Ep0.RxTx[0] = Spk.IdleRate;
                               Ep0.All = 1;      // Only 1 byte transfer to the host
                               USB_CtrlRd();
                               break;
      	    case GET_REPORT:   Ep0.Stage = DFU_RD_STAGE;
                               Ep0.All = Ep0.RxTx[7];
                               Ep0.All <<= 8;
                               Ep0.All += Ep0.RxTx[6];
                               USB_CtrlRd();
                               break;
            case GET_PROTOCOL: USB[EPCON] |= ( RXSTL | TXSTL );
                               break;
      	    case GET_SPK_MAX:
            case GET_SPK_MIN:
            case GET_SPK_CUR:
            case GET_SPK_RES:  Ep0.Stage = USBSPKSTAGE;
                               Ep0.All = Ep0.RxTx[7];
                               Ep0.All <<= 8;
                               Ep0.All += Ep0.RxTx[6];
                               Spk.IDS = Ep0.RxTx[5];
                               Spk.CS = Ep0.RxTx[3];
                               USB_CtrlRd();
                               break;
      	    default:           USB[EPCON] |= ( RXSTL | TXSTL );
                               break;            // Set Rx/Tx STAL 
      	  }
      }
    else                                         // Set Request
      { switch( Ep0.RxTx[1] )                    // Request Code
          { case SET_IDLE:     Ep0.Stage = STATUSSTAGE;
                               Spk.IdleRate = Ep0.RxTx[3];
                               USB[TXCNT] = 0;   // USB will return ACK immediately when receive IN transaction
                               break;
            case SET_REPORT:   Ep0.Stage = DFU_WR_STAGE;
                               Ep0.All = Ep0.RxTx[7];
                               Ep0.All <<= 8;
                               Ep0.All += Ep0.RxTx[6];
                               break;
            case SET_PROTOCOL: USB[EPCON] |= ( RXSTL | TXSTL );
                               break;
            case SET_SPK_CUR:  if ( Ep0.RxTx[0] == SET_SPK_VOL )
                                 { Ep0.Stage = USBSPKSTAGE;
                                   Spk.IDS = Ep0.RxTx[5];
                                   Spk.CS = Ep0.RxTx[3];
                                   if ( Spk.CS == SPK_CS_VOLUME )
                                     Spk.Channel = Ep0.RxTx[2];
                                 }
                               else if ( Ep0.RxTx[0] == SET_FEQ_CTL )
                                 { Ep0.Stage = USBSPKSTAGE;
                                   Spk.CS = SPK_CS_FEQ;
                                 }
                               break;
            default:           USB[EPCON] |= ( RXSTL | TXSTL );
                               break;            // Set Rx/Tx STAL 
          }
      }
  }


void USB_CtrlWr( void )                          // Host Out , USB In ( Only for EPO )
  { Ep0.Buf = Ep0.RxTx;                          // Move Buffer address to RxTx[8] array , Use for USB_CtrlRd();
    USB_Ep0_FIFO();                              // Move Rx Data to RxTxBuf buffer
    if ( Ep0.Stage == SETUPSTAGE )               // if Setup Transection will set Ep0.All = 8
      {	Ep0.All = 0;
        switch( Ep0.RxTx[0] & 0x60 )             // Request Type
          { case STANDARD_REQUEST: USB_Stardard_Request();
                                   break;
            case CLASS_REQUEST:    USB_Class_Request();
                                   break;
            default:               USB[EPCON] |= ( RXSTL | TXSTL );
                                   break;       // Set Rx/Tx STAL 
          }
      }    
  }


void USB_HID_Out( void )
  { BYTE i;

    
    Spk.Busy = SET;
    USB[EPINDEX] = EP1;
    USB[TXDAT] = Spk.Button;
    
    i = DFU_MAX - 1;
    while( i )
      { USB[TXDAT] = CLR;
        i--;
      }
      
    USB[TXCNT] = DFU_MAX;
    
    Spk.IdleRateCnt.B[0] = 0;
    Spk.IdleRateCnt.B[1] = Spk.IdleRate;
    Spk.IdleRateCnt.W <<= 2;
  }


void USB_Int( void )
  { BYTE Status;
    
    
    Status = USB[UPCON];                         // Status in Power Control Register
    
    if ( Status & 0x0F )                         // Into Power Control mode
      { if ( Status & USUS )                     // Suspend mode
          { Status &= 0xF0;
            USB[UPCON] = ( Status | USUS );      // Write "1" to Clear this Flag
            
            Status = USB[UPCON];                 // Status in Power Control Register
            if (( Status & 0x0F ) == 0x00 )      // Into Power Control mode
              { USB[AFCTL] &= ~SIFEN;            // Disable Serial Interface
                Delay_Xms( 2 );
                
                Wm8987l_Power_Down();
                
                USBLED = SET;                    // USB LED Off
                MUTELED = SET;                   // Mute LED Off
                
                PCON |= 0x02;                    // Set CPU(8051) into PowerDown mode
                
                Delay_Xms( 30 );                 // Wait for USB Block ( APLL ) Ready
      	        USB[AFCTL] |=  SIFEN;            // Enable Serial Interface
      	        Delay_Xms( 2 );
              }
          }
      	else
      	  { Delay_Xms( 1 );                      // Wait for USB Block ( APLL ) Ready
      	    
      	    if ( Status & URST )                 // Reset mode
              {	Status &= 0xF0;
                USB[UPCON] = ( Status | URST );  // Write "1" to Clear this Flag
                Initial_USB();
              }
            else if ( Status & URSM )            // Resume mode  
              { Status &= 0xF0;
                
                USB[UPCON] = ( Status | URSM );  // Write "1" to Clear this Flag
              }
            
            if ( Ep0.EmuOk == SET )              // Set USB LED ON after " SET_CONFIGURATION "
      	      USBLED = CLR;                      // USB LED On ( MUTE LED will update at SPK_Status(); )
          }
      }
    else  
      { Status = USB[UIFLG];
        if ( Status & UTXD1 )                    // EP1 Transmit
          { USB[UIFLG] = UTXD1;                  // Write "1" to Clear this Flag
            USB[EPINDEX] = EP1;
            Spk.Busy = CLR;
          }
        else if ( Status & UTXD0 )               // EP0 Transmit
          { USB[UIFLG] = UTXD0;                  // Write "1" to Clear this Flag
            USB[EPINDEX] = EP0;
            USB_CtrlRd();
          }
        else if ( Status & URXD0 )               // EP0 Receive
          { USB[UIFLG] = URXD0;                  // Write "1" to Clear this Flag
            USB[EPINDEX] = EP0;
            USB_CtrlWr();                        // USB Standard Device Request(maybe)
          }
        else if ( Status & ASOFIF )              // Hardware 1m interrupt ( SOF )
          { if ( Status & SOFIF )
              { USB[UIFLG] = SOFIF;
              	SPK_PLL_Divider(); 
              }
            
            USB[UIFLG] = ASOFIF;
            SPK_Status();                        // Volume Up/Down Button and Mute status
            if ( Spk.IdleRate )                  // Set Idle is TRUE
              { if (( Spk.IdleRateCnt.W == CLR )&&( Spk.Busy == CLR ))
              	  USB_HID_Out();
              	else
              	  Spk.IdleRateCnt.W--;
              }
          }
      }
    
    Wm8987l.Cnt--;
    if ( Wm8987l.Cnt == 0 )
      Wm8987l_Power_Up();
  }