#include "reg51.h"
#include "d11_cmds.h"
#include "chap9.des"
#include "io.h"
#define CTRL_BUFFER_SIZE 8

bdata unsigned char DEVICE_STATUS;
sbit REMOTE_WAKEUP = DEVICE_STATUS^1;
sbit SELF_POWERED = DEVICE_STATUS^0;

unsigned char *CUR_LOAD_PTR; //Current Pointer in which data can load from
unsigned char *END_LOAD_PTR; //Pointer to the last data to send to host
bdata unsigned char OPERATIONS_STATUS;
sbit TO_SEND_LAST_ZERO = OPERATIONS_STATUS^0;
sbit CONFIGURED = OPERATIONS_STATUS^1;
sbit WAIT_TRIGGER = OPERATIONS_STATUS^2;

unsigned char BOOT_PROTOCOL;
unsigned char IDLE_TIME;

void D11ClassRequest(struct REQUEST *pReq);
void D11StandardRequest(struct REQUEST *pReq);


void SendDescriptor(void)
{
unsigned char count;

	if ((END_LOAD_PTR - CUR_LOAD_PTR) >= 0)
	{
		for (count = 0; count < CTRL_BUFFER_SIZE; count++)
		{
			DBUFFER[count+1] = *CUR_LOAD_PTR;
			CUR_LOAD_PTR++;
			if (CUR_LOAD_PTR > END_LOAD_PTR)
			{
				DBUFFER[0] = count+1;
				SelectEndpoint(CTRL_IN);
				WriteBuffer();
        			ValidateBuffer();
				return;
			}
		}
		DBUFFER[0] = count;
		SelectEndpoint(CTRL_IN);
		WriteBuffer();
        	ValidateBuffer();
	}
	else
	{
		if (TO_SEND_LAST_ZERO)
		{
    			SendZeroPacket(CTRL_IN);
			TO_SEND_LAST_ZERO = 0;
		}
	}
}


/* ------------------------------------------------------------------------ */
/*  Function : ProcessCtrlInEP();                                           */
/* Depiction : To process Control In Endpoint Event (Host sends IN tokens   */
/*   Read out D11 In interrupt status                                       */
/*   Select D11 In Endpoint and read buffer status                          */
/*   If buffer is empty and last request is a SET_ADDRESS requst            */
/*     Set Hub configured address                                           */
/*   else if it has remaing data packet in buffer                           */
/*     Send out data packet to host                                         */
/* Input     : None                                                         */
/* Output    : None                                                         */
/* ------------------------------------------------------------------------ */
void ProcessCtrlInEP(void)
{
        if (SelectEndpoint(CTRL_IN) == 0x00) //Not Stall and emptied.
	if (ReadEndptStatus(CTRL_IN) & 0x01) //Clears the IN interrupt
		SendDescriptor();
}

/* ------------------------------------------------------------------------ */
/*  Function : ProcessCtrlOutEP();                                          */
/* Depiction : To process Control Out Endpoint Event (Host sends OUT or     */
/*             SETUP tokens)						    */
/*   Read out H11 In interrupt status                                       */
/*   Select H11 In Endpoint and read buffer status                          */
/*   If buffer is empty and last request is a SET_ADDRESS requst            */
/*     Set Hub configured address                                           */
/*   else if it has remaing data packet in buffer                           */
/*     Send out data packet to host                                         */
/* Input     : None                                                         */
/* Output    : None                                                         */
/* ------------------------------------------------------------------------ */
void ProcessCtrlOutEP(void)
{
struct REQUEST data *pReq;
//struct REQUEST data tempReq;

unsigned char CUR_STATUS;

  CUR_STATUS = ReadEndptStatus(CTRL_OUT);

  if (CUR_STATUS & 0X80)
  { //LAST STATUS NOT READ
    if (CUR_STATUS & 0X20) //Overwritten by Setup Token
    {
	SelectEndpoint(CTRL_IN); // Flush the IN Buffer to
	Ack_SETUP();             // Prevent Previous data from
	ClearBuffer();           // being sent out

	SelectEndpoint(CTRL_OUT); // Select the OUT Buffer
        ReadBuffer();             //Read the current Setup Token
	Ack_SETUP();              // Prevent Previous data from
	ClearBuffer();            // being sent out

	if (DBUFFER[0] == 0x08)
	{ //Valid Setup Token

		TO_SEND_LAST_ZERO = 0; //Re-initialise this everytime.
      		pReq = (struct REQUEST *) &DBUFFER[1];

      		if ( DBUFFER[1] & CMD_TYPE )
        		D11ClassRequest(pReq);
      		else
			D11StandardRequest(pReq);
	}
	else
	{ //Invalid Setup Token length
	}
    }
  } else
  if (CUR_STATUS == 0X21)
  { // CURRENT PACKET IS A SETUP TOKEN and NO ERROR
	SelectEndpoint(CTRL_IN); // Flush the IN Buffer to
	Ack_SETUP();             // Prevent Previous data from
	ClearBuffer();           // being sent out

	SelectEndpoint(CTRL_OUT); // Select the OUT Buffer
        ReadBuffer();             //Read the current Setup Token
	Ack_SETUP();              // Prevent Previous data from
	ClearBuffer();            // being sent out

	if (DBUFFER[0] == 0x08)
	{ //Valid Setup Token

		TO_SEND_LAST_ZERO = 0; //Re-initialise this everytime.
      		pReq = (struct REQUEST *) &DBUFFER[1];

      		if ( DBUFFER[1] & CMD_TYPE )
        		D11ClassRequest(pReq);
      		else
			D11StandardRequest(pReq);
	}
	else
	{ //Invalid Setup Token length
	}

  } else
  if (CUR_STATUS & 0X1E)
  { // ERROR CONDITION
	switch (CUR_STATUS & 0X1E)
	{
		case 0x02 : //0001 PID Encoding Error
		case 0x04 : //0010 PID Unknown
		case 0x06 : //0011 Unexpected packet
		case 0x08 : //0100 Token CRC Error
		case 0x0A : //0101 Data CRC Error
		case 0x0C : //0110 Time out Error
		case 0x0E : //0111 Never happens
		case 0x10 : //1000 Unexpected End of Packet
		case 0x12 : //1001 Sent or received NAK
		case 0x14 : //1010 Sent Stall, toekn received Endpt Stalled
		case 0x16 : //1011 Overflow Error
		case 0x1A : //1101 BitStuff Error
		case 0x1E : //1111 Wrong DATA PID
		default :
			break;
        }
  }
}


/* ------------------------------------------------------------------------ */
/*  Function : GetDeviceStatus                                              */
/* Depiction :                                                              */
/* Input     :                                                              */
/* Output    :                                                              */
/* ------------------------------------------------------------------------ */
BYTE GetDeviceStatus(struct REQUEST *pReq)
{
BYTE bOK=1;
  switch ((pReq->bmRequestType & RECIPENT))
  {
    case 0 : /* Device Status */ /* remote wakeup feature */
	  DBUFFER[1] = DEVICE_STATUS;
          break;

    case 1 : /* Interface Status */
  	  DBUFFER[1] = 0;
          break;

    case 2 : /* Endpoint Status */ /* stall feature */
      	  switch  ( LOBYTE(pReq->wIndex) )
	  {
             case 0x00 :
             case 0x80 :
	  	//Always Unstalls Ctrl Endpoint IN or OUT
    	        DBUFFER[1] = 0;
                break;
             case 0x01 : //Reads to see if Endpoint 1 OUT is Stalled
                if (ReadEPStall(ENDPOINT1_OUT) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
	     case 0x81 : //Reads to see if Endpoint 1 IN is Stalled
                if (ReadEPStall(ENDPOINT1_IN) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
             case 0x02 : //Reads to see if Endpoint 2 OUT is Stalled
                if (ReadEPStall(ENDPOINT2_OUT) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
             case 0x82 : //Reads to see if Endpoint 2 IN is Stalled
                if (ReadEPStall(ENDPOINT2_IN) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
             case 0x03 : //Reads to see if Endpoint 3 OUT is Stalled
                if (ReadEPStall(ENDPOINT3_OUT) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
             case 0x83 : //Reads to see if Endpoint 3 IN is Stalled
                if (ReadEPStall(ENDPOINT3_IN) & 0x08) DBUFFER[1] = 1;
		else DBUFFER[1] = 0;
		break;
             default :
		  DBUFFER[1] = 0;
                  bOK=0;
                  break;
          }
	  break;
    default :
         bOK=0;
         break;

  }
  if (bOK)
  {
 	DBUFFER[0] = 2;
  	DBUFFER[2] = 0;
	SelectEndpoint(CTRL_IN);
	WriteBuffer();
        ValidateBuffer();
  }
  return(bOK);
}

/* ------------------------------------------------------------------------ */
/*  Function : SetDeviceFeature                                             */
/* Description : Used to Set Device Feature and Clear Device Feature        */
/* Input     :                                                              */
/* Output    :                                                              */
/* ------------------------------------------------------------------------ */
BYTE SetDeviceFeature(struct REQUEST *pReq)
{
BYTE bOK=1;
  switch (pReq->bmRequestType & RECIPENT ) {
    case 0 : /* device */ /* remote wakeup feature */
        REMOTE_WAKEUP = ( pReq->bRequest == SET_FEATURE_REQ );
      	break;
    case 2 : /* endpoint */ /* stall feature */
      switch  ( LOBYTE(pReq->wIndex) ) {  //%%%%
        case 0x00: /* EP 0 OUT */
          /* Ignore, Control Endpoint Always Unstalls on Setup Token */
          break;
        case 0x80: /* EP 0 IN */
	  SetEndptStatus(CTRL_IN, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x01: /* EP 1 OUT */
	  SetEndptStatus(ENDPOINT1_OUT, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x81: /* EP 1 IN */
	  SetEndptStatus(ENDPOINT1_IN, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x02: /* EP2 OUT */
	  SetEndptStatus(ENDPOINT2_OUT, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x82: /* EP2 IN */
	  SetEndptStatus(ENDPOINT2_IN, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x03: /* EP3 OUT */
	  SetEndptStatus(ENDPOINT3_OUT, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        case 0x83: /* EP3 IN */
	  SetEndptStatus(ENDPOINT3_IN, ( pReq->bRequest == SET_FEATURE_REQ ));
          break;
        default :
          bOK=0;
          break;
      }
      break;
    case 1 : /* interface */ /* No Set or Clear feature for interface */
    default :
      bOK=0;
      break;
  }
  if ( bOK )
    SendZeroPacket(CTRL_IN);
  return(bOK);
}


/* ------------------------------------------------------------------------ */
/*  Function : GetDescriptor                                                */
/* Depiction :                                                              */
/* Input     :                                                              */
/* Output    :                                                              */
/* ------------------------------------------------------------------------ */
BYTE GetDescriptor(struct REQUEST *pReq)
{
BYTE bOK=1;
unsigned int ReqDataLen;

   ReqDataLen = HIBYTE(pReq->wLength) << 8;
   ReqDataLen = LOBYTE(pReq->wLength) | (0xff00 & ReqDataLen);
   switch (pReq->wValue)
   {
	case 0x0001 : /* Device Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(struct DEVICE) )
           		ReqDataLen = sizeof(struct DEVICE);
        	CUR_LOAD_PTR= (unsigned char *) &sDevice;
        	break;
        case 0x0002 : /* Configuration Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(struct CONFIGURATION) )
           		ReqDataLen = sizeof(struct CONFIG);
        	CUR_LOAD_PTR= (unsigned char *) &sConfiguration;
        	break;
	case 0x0003 : /* String Descriptor Language ID */
        	if ( ReqDataLen > (unsigned int) sizeof(LANG_ID) )
           		ReqDataLen = sizeof(LANG_ID);
        	CUR_LOAD_PTR= (unsigned char *) LANG_ID;
		if (ReqDataLen == 4) WAIT_TRIGGER = 1;
        	break;
	case 0x0103 : /* String Descriptor Index 1 */
        	if ( ReqDataLen > (unsigned int) sizeof(struct STRING1) )
           		ReqDataLen = sizeof(struct STRING1);
        	CUR_LOAD_PTR= (unsigned char *) &sSTRING1;
        	break;
	case 0x0203 : /* String Descriptor Index 2 */
        	if ( ReqDataLen > (unsigned int) sizeof(struct STRING2) )
           		ReqDataLen = sizeof(struct STRING2);
        	CUR_LOAD_PTR= (unsigned char *) &sSTRING2;
        	break;
	case 0x0004 : /* Interface Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(struct INTERFACE) )
           		ReqDataLen = sizeof(struct INTERFACE);
        	CUR_LOAD_PTR= (unsigned char *) &sConfiguration.sInterface;
        	break;
	case 0x0005 : /* Endpoint Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(struct ENDPOINT) )
           		ReqDataLen = sizeof(struct ENDPOINT);
        	CUR_LOAD_PTR= (unsigned char *) &sConfiguration.sEndpoint1;
        	break;
	case 0x0021 : /* HID Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(struct HIDDESC) )
           		ReqDataLen = sizeof(struct HIDDESC);
        	CUR_LOAD_PTR= (unsigned char *) &sConfiguration.sHIDDesc;
        	break;
	case 0x0022 : /*Report Descriptor */
        	if ( ReqDataLen > (unsigned int) sizeof(REPORT_DESCRIPTOR) )
           		ReqDataLen = sizeof(REPORT_DESCRIPTOR);
        	CUR_LOAD_PTR= (unsigned char *) REPORT_DESCRIPTOR;
        	break;
	default :
        	bOK=0; //Send a Stall for Unknown descriptor type
        	break;
   }
   if (bOK)
   {
	END_LOAD_PTR = CUR_LOAD_PTR + ReqDataLen - 1;
	TO_SEND_LAST_ZERO = ((ReqDataLen % CTRL_BUFFER_SIZE) == 0);
        SendDescriptor();
   }
   return(bOK);
}



void D11StandardRequest(struct REQUEST *pReq)
{
BYTE bOK=1;
BYTE endpoint_state=0;

  switch ( pReq->bRequest ) {
    case GET_STATUS_REQ :
      bOK=GetDeviceStatus(pReq);
      break;
    case CLEAR_FEATURE_REQ :
    case SET_FEATURE_REQ :
      bOK=SetDeviceFeature(pReq);
      break;
    case SET_ADDRESS_REQ :
      if (D11_INT_ == 0) //clears all the interrupt first
      {
		UpdateIntReg();
		if (ENDPT_INT & CTRL_ENDPT_OUT) ReadEndptStatus(CTRL_OUT);
		if (ENDPT_INT & CTRL_ENDPT_IN) ReadEndptStatus(CTRL_IN);
		if (ENDPT_INT & ENDPT1_OUT) ReadEndptStatus(ENDPOINT1_OUT);
		if (ENDPT_INT & ENDPT1_IN) ReadEndptStatus(ENDPOINT1_IN);
		if (ENDPT_INT & ENDPT2_OUT) ReadEndptStatus(ENDPOINT2_OUT);
		if (ENDPT_INT & ENDPT2_IN) ReadEndptStatus(ENDPOINT2_IN);
		if (OTHER_INT & ENDPT3_OUT) ReadEndptStatus(ENDPOINT3_OUT);
		if (OTHER_INT & ENDPT3_IN) ReadEndptStatus(ENDPOINT3_IN);
      }
      SendZeroPacket(CTRL_IN);
      while(D11_INT_);
      SetAddress(LOBYTE(pReq->wValue) | 0x80); //Set to new address
      SetEndptEnable(0x01);
      ReadEndptStatus(CTRL_IN); //Clears the IN interrupt
      break;
    case GET_DESCRIPTOR_REQ :
      bOK=GetDescriptor(pReq);
      break;
    case GET_CONFIGURATION_REQ :
      DBUFFER[0] = 1;
      if (CONFIGURED) DBUFFER[1] = 1;
      else DBUFFER[1] = 0;
      SelectEndpoint(CTRL_IN);
      WriteBuffer();
      ValidateBuffer();
      break;
    case SET_CONFIGURATION_REQ :
      switch ( pReq->wValue )
      {
          case 0x0100 :
                CONFIGURED = 1;
		    Port1_Power();
                SetEndptEnable(0x02); //Enable all functional endpoints
    		    SendZeroPacket(CTRL_IN);
                break;
          case 0x0000 :
                CONFIGURED = 0;
                SetEndptEnable(0x00); //Enable all functional endpoints
    		    SendZeroPacket(CTRL_IN);
                break;
          default :
                break;
      }
      break;
    case GET_INTERFACE_REQ :
      DBUFFER[0] = 1;
      DBUFFER[1] = 0;
      SelectEndpoint(CTRL_IN);
      WriteBuffer();
      ValidateBuffer();
      break;
    case SET_INTERFACE_REQ :
      SendZeroPacket(CTRL_IN);
      break;
    /* non-implement requests, send STALL to host IN transaction*/
    case SYNCH_FRAME_REQ :
    case SET_DESCRIPTOR_REQ :
    default :
      bOK=0;
      break;
  }
  if ( !bOK ) SetEndptStatus(CTRL_IN, 0x01); //Stalls Endpoint0 IN
}

#define GET_IDLE_REQ 0x02
#define SET_IDLE_REQ 0x0A
#define GET_CPROTOCOL_REQ 0x03
#define SET_CPROTOCOL_REQ 0x0B

void D11ClassRequest(struct REQUEST *pReq)
{
BYTE bOK=1;
  switch ( pReq->bRequest ) {
    case GET_IDLE_REQ :
      DBUFFER[0] = 1;
      DBUFFER[1] = IDLE_TIME;
      SelectEndpoint(CTRL_IN);
      WriteBuffer();
      ValidateBuffer();
      break;
    case SET_CPROTOCOL_REQ :
      BOOT_PROTOCOL = LOBYTE(pReq->wValue);
      SendZeroPacket(CTRL_IN);
      break;
    case GET_CPROTOCOL_REQ :
      DBUFFER[0] = 1;
      DBUFFER[1] = BOOT_PROTOCOL;
      SelectEndpoint(CTRL_IN);
      WriteBuffer();
      ValidateBuffer();
      break;
    case SET_IDLE_REQ :
      IDLE_TIME = HIBYTE(pReq->wValue);
      SendZeroPacket(CTRL_IN);
      break;
    default :
      bOK=0;
      break;
  }
  if ( !bOK ) SetEndptStatus(CTRL_IN, 0x01); //Stalls Endpoint0 IN 
}


