// ============================================================================
// IMPORTANT
//
// The project specific descriptor table must exist !!!
// It declares the following symbols:
//		- DscrString
//		- DscrDevice
//		- DscrDeviceQual
//		- DscrHsConfig
//		- DscrFsConfig
// ============================================================================
#include <fx2.h>
#include <fx2_regs.h>

xdata			DEVICE_DSCR 	xdata *pDscrDevice;
xdata			DEVICEQUAL_DSCR	xdata *pDscrDeviceQual;

extern xdata	CONFIG_DSCR		xdata *pDscrMainConfig;
extern xdata	CONFIG_DSCR		xdata *pDscrOthrConfig;
extern xdata	CONFIG_DSCR		xdata *pDscrFsConfig;
extern xdata	CONFIG_DSCR		xdata *pDscrHsConfig;


data			STRING_DSCR 	xdata *pDscrString;

STRING_DSCR xdata * GetStringDscr( BYTE index);

bool	(*DR_VendorCommand)() = 0;

// ============================================================================
// SUDAV (device request parser)
//
// The following commands have no default implementation:
//	- SC_GET_INTERFACE
//	- SC_SET_INTERFACE
//	- SC_GET_CONFIGURATION
//	- SC_SET_CONFIGURATION
//
// These commands usually result in changing the hardware configuration, which
// is different in most device.
// ============================================================================
void tri_sudav()
{
	STRING_DSCR xdata *ptr;						  
	BYTE		xdata  cfg;

	switch( SETUPDAT[1])
	{
		// ------------------------------------------------
		// Get Descriptor
		// ------------------------------------------------
		case SC_GET_DESCRIPTOR:
			switch( SETUPDAT[3])
			{
			 	case GD_DEVICE:
					SUDPTRH = MSB(pDscrDevice);
					SUDPTRL = LSB(pDscrDevice);
					break;

				case GD_DEVICE_QUALIFIER:
					// Only for HighSpeed capable devices
					SUDPTRH = MSB(pDscrDeviceQual);
					SUDPTRL = LSB(pDscrDeviceQual);
					break;

				case GD_CONFIGURATION:
					SUDPTRH = MSB(pDscrMainConfig);
					SUDPTRL = LSB(pDscrMainConfig);
					break;

				case GD_OTHER_SPEED_CONFIG:
					SUDPTRH = MSB(pDscrOthrConfig);
					SUDPTRL = LSB(pDscrOthrConfig);
					break;

				case GD_STRING:
	                if( ptr = GetStringDscr(SETUPDAT[2]))
                	{
	                    SUDPTRH	= MSB(ptr);
                    	SUDPTRL = LSB(ptr);
                	}
                	else
	                    FX2_STALL_EP0();

	                break;

				default:
					FX2_STALL_EP0();
					break;
			}
			break;

		// ------------------------------------------------
		// Get Status
		// ------------------------------------------------
		case SC_GET_STATUS:
			switch( SETUPDAT[0])
			{
				case GS_DEVICE:
//					EP0BUF[0]	= ((BYTE)Rwuen << 1) | (BYTE)SelfPower;
					EP0BUF[0]	= 0;
                	EP0BUF[1]	= 0;
                	EP0BCH		= 0;
                	EP0BCL		= 2;
					break;

	            case GS_INTERFACE:
                	EP0BUF[0]	= 0;
                	EP0BUF[1]	= 0;
                	EP0BCH		= 0;
                	EP0BCL		= 2;
					break;

              	case GS_ENDPOINT:
//                	EP0BUF[0]	= (*(BYTE xdata *)epcs(SETUPDAT[4])) & bmEPSTALL;
					EP0BUF[0]	= 0;
                	EP0BUF[1]	= 0;
                	EP0BCH		= 0;
                	EP0BCL		= 2;
					break;

              	default:
                	FX2_STALL_EP0();
                	break;
			}
			break;


		// ------------------------------------------------
		// Set Configuration
		// ------------------------------------------------
		case SC_SET_CONFIGURATION:
			cfg = SETUPDAT[2];
			break;

		// ------------------------------------------------
		// Vendor command
		// ------------------------------------------------
		default:
			if( !DR_VendorCommand)
			{
			}

			else if( !DR_VendorCommand())
			{
			}
	}

	// --------------------------------------------------------------
	// Acknowledge handshake phase of device request.
	// --------------------------------------------------------------
	EP0CS |= bmHSNAK;
}

// ============================================================================
// GetStringDscr
// ============================================================================
STRING_DSCR xdata * GetStringDscr( BYTE index)
{
    STRING_DSCR xdata * dscr = pDscrString;

    while( dscr->type == DSCR_STRING)
    {
        if( !index--)
            return dscr;

        dscr = (STRING_DSCR xdata *)((WORD)dscr +dscr->length);
    }

    return 0;
}
