/******************************************************************************
*
* Copyright (C) 2006 Vreelin Engineering, Inc.  All Rights Reserved.
* (c) Copyright 2007-2013 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
******************************************************************************/
/*****************************************************************************/
/**
 * @file xusb_cp9.c
 *
 * This file contains the USB Chapter 9 related functions.
 *
 * @note	None.
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Ver   Who  Date     Changes
 * ----- ---- -----------------------------------------------------------------
 * 1.00a hvm  2/22/07 First release
 * 1.01a hvm  5/30/07 Moved the USB class specific command processing to
 *		      application files.
 * 3.00a hvm  11/18/09 Updated to use HAL processor APIs.
 *		       XUsb_mReadReg is renamed to XUsb_ReadReg and
 *		       XUsb_mWriteReg is renamed to XUsb_WriteReg.
 * 3.02a hvm  08/16/10 Updated with the little endian support changes.
 * 4.00a hvm  12/20/10 Updated SetInterface function with microphone case
 *			support.
 *
 * </pre>
 *****************************************************************************/
/***************************** Include Files *********************************/

#include "xusb_cp9.h"
#include <xparameters.h>

#undef XUSB_CH9_DEBUG

#ifdef XUSB_CH9_DEBUG
#include "stdio.h"
#endif

/************************** Constant Definitions ******************************/

/************************** Variable Definitions ******************************/

IntChar UsbMemData;		/* Dual Port memory */

/*
 * Instance of the Chapter 9 command buffer.
 */
USB_CMD_BUF Ch9_CmdBuf;

/*
 * Maximum control pkt size.
 */
u16 MaxControlSize = 8;

/*
 * Standard USB structure instances.
 */
extern USB_STD_DEV_DESC DeviceDescriptor;
extern USB_STD_QUAL_DESC QualifierDescriptor;
extern FPGA1_CONFIGURATION HsUsbConfig;
extern FPGA1_CONFIGURATION FsUsbConfig;
extern USB_STD_STRING_DESC LangId;
extern USB_STD_STRING_MAN_DESC Manufacturer;
extern USB_STD_STRING_PS_DESC ProductString;
extern USB_STD_STRING_SN_DESC SerialNumber;

#ifdef HID_DEVICES
extern USB_STD_HID_DESC HidDescriptor;
#endif

#ifdef USB_KEYBOARD
const unsigned char ReportDesc[0x2b] =   // Report descriptor
	{
	0x05,0x01,		/* Usage Page (generic desktop) */
	0x09,0x06,		/* Usage (keyboard) */
	0xA1,0x01,		/* Collection */
	0x05,0x07,		/*   Usage Page 7 (keyboard/keypad) */
	0x19,0xE0,		/*   Usage Minimum = 224 */
	0x29,0xE7,		/*   Usage Maximum = 231 */
	0x15,0x00,		/*   Logical Minimum = 0 */
	0x25,0x01,		/*   Logical Maximum = 1 */
	0x75,0x01,		/*   Report Size = 1 */
	0x95,0x08,		/*   Report Count = 8 */
	0x81,0x02,		/*  Input(Data,Variable,Absolute) */
	0x95,0x01,		/*   Report Count = 1 */
	0x75,0x08,		/*   Report Size = 8 */
	0x81,0x01,		/*  Input(Constant) */
	0x19,0x00,		/*   Usage Minimum = 0 */
	0x29,0x65,		/*   Usage Maximum = 101 */
	0x15,0x00,		/*   Logical Minimum = 0 */
	0x25,0x65,		/*   Logical Maximum = 101 */
	0x75,0x08,		/*   Report Size = 8 */
	0x95,0x01,		/*   Report Count = 1 */
	0x81,0x00,		/*  Input(Data,Variable,Array) */
	0xC0};			/* End Collection */
#endif

#ifdef USB_MOUSE
const unsigned char ReportDesc[0x34] =   // Report descriptor
	{
	0x05,0x01,		/* Usage Page (generic desktop) */
	0x09,0x02,		/* Usage (mouse) */
	0xA1,0x01,		/* Collection */
	0x09,0x01,		/*   Usage Page 7 () */
	0xA1,0x00,		/*   Usage Minimum = 224 */
	0x05,0x09,		/*   Usage Maximum = 231 */
	0x19,0x01,		/*   Logical Minimum = 0 */
	0x29,0x03,		/*   Logical Maximum = 1 */
	0x15,0x00,		/*   Report Size = 1 */
	0x25,0x01,		/*   Report Count = 8 */
	0x95,0x03,		/*  Input(Data,Variable,Absolute) */
	0x75,0x01,		/*   Report Count = 1 */
	0x81,0x02,		/*   Report Size = 8 */
	0x95,0x01,		/*  Input(Constant) */
	0x75,0x05,		/*   Usage Minimum = 0 */
	0x81,0x01,		/*   Usage Maximum = 101 */
	0x05,0x01,		/*   Logical Minimum = 0 */
	0x09,0x30,		/*   Logical Maximum = 101 */
	0x09,0x31,		/*   Report Size = 8 */
	0x09,0x38,
	0x15,0x81,		/*   Report Count = 1 */
	0x25,0x7F,		/*  Input(Data,Variable,Array) */
	0x75,0x08,
	0x95,0x03,
	0x81,0x06,
	0xC0,
	0xC0};			/* End Collection */
#endif

/************************** Function Prototypes *******************************/

/******************************************************************************/
/**
* This routine is called when an OUT transaction for Endpoint Zero is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note		None.
*
******************************************************************************/
void EP0ProcessOutToken(XUsb * InstancePtr)
{
	u8 Count;
	u8 *RamBase;
	u16 Index;

	switch (Ch9_CmdBuf.SetupSeqRX) {
	case STATUS_PHASE:
		/*
		 * This resets both state machines for the next
		 * Setup packet.
		 */
		Ch9_CmdBuf.SetupSeqRX = SETUP_PHASE;
		Ch9_CmdBuf.SetupSeqTX = SETUP_PHASE;
		break;

	case DATA_PHASE:

		Count = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
					XUSB_EP_BUF0COUNT_OFFSET);
			/*
			 * Copy the data to be received from the DPRAM.
			*/
			RamBase = (u8 *) (InstancePtr->Config.BaseAddress +
					((InstancePtr->DeviceConfig.Ep[0].
						RamBase) << 2));

			for (Index = 0; Index < Count; Index++) {

				*Ch9_CmdBuf.ContReadPtr++ = *RamBase++;
			}

			Ch9_CmdBuf.ContReadCount += Count;

			if (Ch9_CmdBuf.Word3.wLength == Ch9_CmdBuf.ContReadCount) {
				Ch9_CmdBuf.SetupSeqRX = STATUS_PHASE;
				ExecuteCommand(InstancePtr);
			} else {
				/*
				 * Set the Tx packet size and the Tx enable bit.
				 */
				XUsb_WriteReg(InstancePtr->Config.BaseAddress,
					XUSB_EP_BUF0COUNT_OFFSET, Count);

				XUsb_WriteReg(InstancePtr->Config.BaseAddress,
					XUSB_BUFFREADY_OFFSET, 1);

				InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;
			}
			break;

	default:
		break;
	}
}

/******************************************************************************/
/**
* This routine is called when IN transaction for Endpoint Zero is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note     	None.
*
******************************************************************************/
void EP0ProcessInToken(XUsb * InstancePtr)
{
	u32 EpCfgReg;

	switch (Ch9_CmdBuf.SetupSeqTX) {
	case STATUS_PHASE:
		if (Ch9_CmdBuf.Byte1.bRequest == SET_ADDRESS) {
			/*
			 * Set the address of the device.
			 */
			XUsb_SetDeviceAddress(InstancePtr,
					      Ch9_CmdBuf.Word1.Byte23.
					      bDescriptorIndex);
		}
		else if (Ch9_CmdBuf.Byte1.bRequest == SET_FEATURE) {
			if (Ch9_CmdBuf.Byte0.bmRequestType ==
			    STANDARD_OUT_DEVICE) {
#ifdef __LITTLE_ENDIAN__
			Ch9_CmdBuf.Word1.wValue =
			((u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) |
			(u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorType	<< 8));
#endif

				if (Ch9_CmdBuf.Word1.wValue == TEST_MODE) {
					XUsb_SetTestMode(InstancePtr, TEST_J,
							 NULL);
				}
			}
		}
		break;

	case DATA_PHASE:
		if (Ch9_CmdBuf.ContWriteCount == 0) {
			/*
			 * We're done with data transfer, next
			 * will be zero length OUT with data toggle of
			 * 1. Setup data_toggle.
			 */
			EpCfgReg = XUsb_ReadReg(InstancePtr->Config.
						 BaseAddress,
						 InstancePtr->
						 EndPointOffset[0]);
			EpCfgReg |= XUSB_EP_CFG_DATA_TOGGLE_MASK;
			XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				       InstancePtr->EndPointOffset[0],
				       EpCfgReg);
			XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				       (InstancePtr->EndPointOffset[0] +
					XUSB_EP_BUF0COUNT_OFFSET), 0);
			XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				       XUSB_BUFFREADY_OFFSET, 1);
			InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;

			Ch9_CmdBuf.SetupSeqTX = STATUS_PHASE;

		}
		else {
			LoadEP0(InstancePtr);
		}
		break;

	default:
		break;
	}

}

/******************************************************************************/
/**
* This routine is called when a chapter 9 command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	The setup request value to be processed by the upper layer.
*
* @note     	None.
*
******************************************************************************/
int Chapter9(XUsb * InstancePtr)
{
	volatile unsigned int *RamBase;

	/*
	 * Load up the chapter 9 command buffer.
	 */
	RamBase = (unsigned int *) (InstancePtr->Config.BaseAddress +
					XUSB_SETUP_PKT_ADDR_OFFSET);
	/*
	 * Get the first 4 bytes of the setup packet.
	 */
	UsbMemData.Word = *RamBase;
	Ch9_CmdBuf.Byte0.bmRequestType = UsbMemData.Byte.Zero;
	Ch9_CmdBuf.Byte1.bRequest = UsbMemData.Byte.One;
	Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex = UsbMemData.Byte.Two;
	Ch9_CmdBuf.Word1.Byte23.bDescriptorType = UsbMemData.Byte.Three;

	/*
	 * Get the last 4 bytes of the setup packet.
	 */
	RamBase += 1;
	UsbMemData.Word = *RamBase;

	/*
	 * Byte swapping for next 4 bytes for BE machines is defined in
	 * the different layout of BECB verses LECB.
	 */
#ifdef __LITTLE_ENDIAN__
	Ch9_CmdBuf.Word2.Byte45.Byteh = UsbMemData.Byte.Zero;
	Ch9_CmdBuf.Word2.Byte45.Bytel = UsbMemData.Byte.One;
	Ch9_CmdBuf.Word3.Byte67.Byteh = UsbMemData.Byte.Two;
	Ch9_CmdBuf.Word3.Byte67.Bytel = UsbMemData.Byte.Three;
#else
	Ch9_CmdBuf.Word2.Byte45.Bytel = UsbMemData.Byte.Zero;
	Ch9_CmdBuf.Word2.Byte45.Byteh = UsbMemData.Byte.One;
	Ch9_CmdBuf.Word3.Byte67.Bytel = UsbMemData.Byte.Two;
	Ch9_CmdBuf.Word3.Byte67.Byteh = UsbMemData.Byte.Three;
#endif
	/*
	 * Restore ReadPtr to data buffer.
	 */
	Ch9_CmdBuf.ContReadPtr = &Ch9_CmdBuf.ContReadDataBuffer[0];

	if (Ch9_CmdBuf.Byte0.bmRequestType & DIR_DEVICE_TO_HOST) {
		/*
		 * Execute the get command.
		 */
		Ch9_CmdBuf.SetupSeqRX = STATUS_PHASE;
		Ch9_CmdBuf.SetupSeqTX = DATA_PHASE;
		return (ExecuteCommand(InstancePtr));
	}
	else {
		/*
		 * Execute the put command.
		 */
		Ch9_CmdBuf.SetupSeqRX = DATA_PHASE;
		Ch9_CmdBuf.SetupSeqTX = STATUS_PHASE;
		if (Ch9_CmdBuf.Word3.wLength == 0) {
			return (ExecuteCommand(InstancePtr));
		}
	}
	/*
	 *  Control should never reach here
	 */
	return XST_FAILURE;
}

/******************************************************************************/
/**
* This function executes the chapter 9 command processing
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	The request value to be processed by the upper layer if the
*		request is not handled.
*		XST_SUCCESS if the request is successfully processed.
*
* @note		None.
*
******************************************************************************/
int ExecuteCommand(XUsb * InstancePtr)
{

	if ((Ch9_CmdBuf.Byte0.bmRequestType & TYPE_MASK) == TYPE_STANDARD) {
		/*
		 * Process the chapter 9 command.
		 */
		switch (Ch9_CmdBuf.Byte1.bRequest) {
		case GET_STATUS:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Get Status \r\n");
#endif
			GetStatus(InstancePtr);
			break;

		case CLEAR_FEATURE:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Clear Feature \r\n");
#endif
			SetClearFeature(InstancePtr, FALSE);
			break;

		case SET_FEATURE:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Set Feature \r\n");
#endif
			SetClearFeature(InstancePtr, TRUE);
			break;

		case SET_ADDRESS:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Set address \r\n");
#endif
			SetupControlWriteStatusStage(InstancePtr);
			break;

		case GET_DESCRIPTOR:
			GetDescriptor(InstancePtr);
			break;

		case SET_DESCRIPTOR:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Set Descriptor  \r\n");
#endif
			SetDescriptor(InstancePtr);
			break;

		case GET_CONFIGURATION:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Get Configuration  \r\n");
#endif
			GetConfiguration(InstancePtr);
			break;

		case SET_CONFIGURATION:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Set Configuration  \r\n");
#endif
			SetConfiguration(InstancePtr);
			break;

		case GET_INTERFACE:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Get Interface  \r\n");
#endif
			GetInterface(InstancePtr);
			break;

		case SET_INTERFACE:
#ifdef	XUSB_CH9_DEBUG
			xil_printf("Set Interface  \r\n");
#endif
			SetInterface(InstancePtr);
			break;

		case SYCH_FRAME:
			break;

		default:
			/*
			 * The default is to stall the end point zero.
			 */
			XUsb_EpStall(InstancePtr, 0);
			break;
		}

	}
	else if ((Ch9_CmdBuf.Byte0.bmRequestType & TYPE_MASK) == TYPE_CLASS) {
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Sub class code %d \r\n", Ch9_CmdBuf.Byte1.bRequest);
#endif
		return (Ch9_CmdBuf.Byte1.bRequest);
	}
	else {
		/*
		 * Unsupported command. Stall the end point.
		 */
		XUsb_EpStall(InstancePtr, 0);
	}
	return XST_SUCCESS;
}

/******************************************************************************
		Start of Chapter 9 Commands
******************************************************************************/

/*****************************************************************************/
/**
* This function responds to the GET_INTERFACE command.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note     	None.
*
******************************************************************************/
void GetInterface(XUsb * InstancePtr)
{
	u32 *RamBase;

#ifdef __LITTLE_ENDIAN__
	Ch9_CmdBuf.Word1.wValue =
		((u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) |
		(u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorType	<< 8));
#endif

	if (Ch9_CmdBuf.Word1.wValue == 0) {
		RamBase = (u32 *) (InstancePtr->Config.BaseAddress +
					((InstancePtr->DeviceConfig.Ep[0].
					 RamBase) << 2));
		UsbMemData.Word = 0x0;
		*RamBase = UsbMemData.Word;
		InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;

		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			       (InstancePtr->EndPointOffset[0] +
				XUSB_EP_BUF0COUNT_OFFSET), 1);
		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				XUSB_BUFFREADY_OFFSET, 1);

	}
	else {
		XUsb_EpStall(InstancePtr, 0);
	}

}

/******************************************************************************/
/**
* This function responds to the SET_INTERFACE command.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note     	None.
*
******************************************************************************/
void SetInterface(XUsb * InstancePtr)
{
	if ((Ch9_CmdBuf.Word1.wValue == 0) && (Ch9_CmdBuf.Word2.wIndex == 0)) {
		SetupControlWriteStatusStage(InstancePtr);
	}
	else {
#ifdef MICROPHONE
 		SetupControlWriteStatusStage(InstancePtr);
#else
		XUsb_EpStall(InstancePtr, 0);
#endif
	}

}

/******************************************************************************/
/**
 * This function sets the basic Control status words.
 *
 * @param	InstancePtr is a pointer to the XUsb instance of the controller.
 *
 * @return 	None.
 *
 * @note     	None.
 *
 ******************************************************************************/
void SetupControlWriteStatusStage(XUsb * InstancePtr)
{
	u32 EpCfgReg;

	EpCfgReg = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
				 InstancePtr->EndPointOffset[0]);
	EpCfgReg |= XUSB_EP_CFG_DATA_TOGGLE_MASK;

	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
		       InstancePtr->EndPointOffset[0], EpCfgReg);
	InstancePtr->DeviceConfig.Ep[0].Buffer0Count = 0;
	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			(InstancePtr->EndPointOffset[0] +
			XUSB_EP_BUF0COUNT_OFFSET), 0);
	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			XUSB_BUFFREADY_OFFSET, 1);
}

/******************************************************************************/
/**
* This routine is called when a GET_STATUS command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note     	None.
*
******************************************************************************/
void GetStatus(XUsb * InstancePtr)
{
	u32 *RamBase;
	u8 EndPoint;

	UsbMemData.Word = 0x0;
	RamBase = (u32 *) (InstancePtr->Config.BaseAddress +
			((InstancePtr->DeviceConfig.Ep[0].RamBase) << 2));

	switch (Ch9_CmdBuf.Byte0.bmRequestType) {
	case STANDARD_IN_DEVICE:
		UsbMemData.Byte.Zero = 0x01;
		UsbMemData.Byte.One = 0x00;

		*RamBase = UsbMemData.Word;

		InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;
		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			       (InstancePtr->EndPointOffset[0] +
				XUSB_EP_BUF0COUNT_OFFSET), 2);
		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			       XUSB_BUFFREADY_OFFSET, 1);
		break;

	case STANDARD_IN_INTERFACE:
		if ((Ch9_CmdBuf.Word2.wIndex > 0) &&
		    (Ch9_CmdBuf.Word2.wIndex <= MAX_INTERFACES)) {
			UsbMemData.Byte.Zero = 0;
			UsbMemData.Byte.One = 0;
			*RamBase = UsbMemData.Word;
			InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;
			XUsb_WriteReg(InstancePtr->Config.
				BaseAddress, (InstancePtr->EndPointOffset
					[0] + XUSB_EP_BUF0COUNT_OFFSET),
				       2);
			XUsb_WriteReg(InstancePtr->Config.BaseAddress,
					XUSB_BUFFREADY_OFFSET, 1);
		}
		else {
			XUsb_EpStall(InstancePtr, 0);
		}
		break;

	case STANDARD_IN_ENDPOINT:
		EndPoint = (unsigned int) (Ch9_CmdBuf.Word2.wIndex & 0x07);
		UsbMemData.Byte.Zero =
			(u8) (((XUsb_ReadReg(InstancePtr->Config.BaseAddress,
						InstancePtr->
						EndPointOffset[EndPoint]))
						& XUSB_EP_CFG_STALL_MASK) >>
						XUSB_EP_CFG_STALL_SHIFT);
		UsbMemData.Byte.One = 0;

		*RamBase = UsbMemData.Word;

		InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;
		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				(InstancePtr->EndPointOffset[0] +
				XUSB_EP_BUF0COUNT_OFFSET), 2);
		XUsb_WriteReg(InstancePtr->Config.BaseAddress,
				XUSB_BUFFREADY_OFFSET, 1);
		break;

	default:
		/*
		 * The default is to stall the end point.
		 */
		XUsb_EpStall(InstancePtr, 0);
		break;
	}
}

/******************************************************************************/
/**
* This routine is called when a GET_DESCRIPTOR command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note     	None.
*
******************************************************************************/
void GetDescriptor(XUsb * InstancePtr)
{
	switch (Ch9_CmdBuf.Word1.Byte23.bDescriptorType) {
	case DEVICE_DESCR:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Get Dev Decriptor \r\n");
#endif
		if (InstancePtr->DeviceConfig.CurrentSpeed ==
			XUSB_EP_HIGH_SPEED) {
			Ch9_CmdBuf.ContWritePtr =
				(unsigned char *) &DeviceDescriptor;
		}
		else {
			Ch9_CmdBuf.ContWritePtr = (u8 *) &DeviceDescriptor;
		}
		Ch9_CmdBuf.ContWriteCount = sizeof(USB_STD_DEV_DESC);
		if (Ch9_CmdBuf.ContWriteCount > Ch9_CmdBuf.Word3.wLength) {
			Ch9_CmdBuf.ContWriteCount = Ch9_CmdBuf.Word3.wLength;
		}
		break;

	case QUALIFIER_DESCR:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Get Qua Decriptor \r\n");
#endif
		Ch9_CmdBuf.ContWritePtr =
			(unsigned char *) &QualifierDescriptor;
		Ch9_CmdBuf.ContWriteCount = sizeof(USB_STD_QUAL_DESC);
		if (Ch9_CmdBuf.ContWriteCount > Ch9_CmdBuf.Word3.wLength) {
			Ch9_CmdBuf.ContWriteCount = Ch9_CmdBuf.Word3.wLength;
		}
		break;

	case CONFIG_DESCR:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Get Config Decriptor \r\n");
#endif
		if (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex <=
		    DeviceDescriptor.bNumConfigurations) {
			switch (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) {
			case 0:
				/*
				 * Duplicate this for each configuration
				 * supported.
				 */
				if (InstancePtr->DeviceConfig.
				    CurrentSpeed == XUSB_EP_HIGH_SPEED) {
#ifdef	XUSB_CH9_DEBUG
					xil_printf("High Speed  \r\n");
#endif
					HsUsbConfig.stdCfg.bType = CONFIG_DESCR;
					Ch9_CmdBuf.ContWritePtr =
						(u8 *) &HsUsbConfig;
					Ch9_CmdBuf.ContWriteCount =
						HsUsbConfig.stdCfg.bTotalLength;
				}
				else {
					FsUsbConfig.stdCfg.bType = CONFIG_DESCR;
					Ch9_CmdBuf.ContWritePtr =
						(u8 *) &FsUsbConfig;
					Ch9_CmdBuf.ContWriteCount =
						FsUsbConfig.stdCfg.bTotalLength;
				}
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;

			default:
				XUsb_EpStall(InstancePtr, 0);
				goto Func_Exit7;
				break;
			}
		}
		else {
			XUsb_EpStall(InstancePtr, 0);
			goto Func_Exit7;
		}
		break;

	case OSD_CONFIG_DESCR:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Get OSD Config Decriptor \r\n");
#endif
		if (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex <=
		    DeviceDescriptor.bNumConfigurations) {
			switch (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) {
			case 0:
				/*
				 * Duplicate this for each
				 * configuration supported.
				 */
				if (InstancePtr->DeviceConfig.
				    CurrentSpeed == XUSB_EP_HIGH_SPEED) {
					FsUsbConfig.stdCfg.bType =
						OSD_CONFIG_DESCR;
					Ch9_CmdBuf.ContWritePtr =
						(u8 *) &FsUsbConfig;
					Ch9_CmdBuf.ContWriteCount =
						FsUsbConfig.stdCfg.bTotalLength;
				}
				else {
					HsUsbConfig.stdCfg.bType =
						OSD_CONFIG_DESCR;
					Ch9_CmdBuf.ContWritePtr =
						(u8 *) &HsUsbConfig;
					Ch9_CmdBuf.ContWriteCount =
						HsUsbConfig.stdCfg.bTotalLength;
				}
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;

			default:
				XUsb_EpStall(InstancePtr, 0);
				goto Func_Exit7;
				break;
			}
		}
		else {
			XUsb_EpStall(InstancePtr, 0);
			goto Func_Exit7;
		}
		break;

	case STRING_DESCR:
		if (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex <= 3) {
			switch (Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) {
			case 0:
				/*
				 * Set the language ID's.
				 */
#ifdef	XUSB_CH9_DEBUG
				xil_printf("Get LangId  \r\n");
#endif
				Ch9_CmdBuf.ContWritePtr =
					(unsigned char *) &LangId;
				Ch9_CmdBuf.ContWriteCount = LangId.bLength;
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;

			case 1:
				/*
				 * Set the Manufacturer's String.
				 */
#ifdef	XUSB_CH9_DEBUG
				xil_printf("Get Manuferer  \r\n");
#endif
				Ch9_CmdBuf.ContWritePtr =
					(unsigned char *) &Manufacturer;
				Ch9_CmdBuf.ContWriteCount =
					Manufacturer.bLength;
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;

			case 2:
				/*
				 * Set the Product String.
				 */
#ifdef	XUSB_CH9_DEBUG
				xil_printf("Get Product Id  \r\n");
#endif
				Ch9_CmdBuf.ContWritePtr =
					(unsigned char *) &ProductString;
				Ch9_CmdBuf.ContWriteCount =
					ProductString.bLength;
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;

			case 3:
				/*
				 * Set the Serial Number String.
				 */
#ifdef	XUSB_CH9_DEBUG
				xil_printf("Get Serial No  \r\n");
#endif
				Ch9_CmdBuf.ContWritePtr =
					(unsigned char *) &SerialNumber;
				Ch9_CmdBuf.ContWriteCount =
					SerialNumber.bLength;
				if (Ch9_CmdBuf.ContWriteCount >
				    Ch9_CmdBuf.Word3.wLength) {
					Ch9_CmdBuf.ContWriteCount =
						Ch9_CmdBuf.Word3.wLength;
				}
				break;
			default:
				XUsb_EpStall(InstancePtr, 0);
				goto Func_Exit7;
				break;
			}
		}
		else {
			XUsb_EpStall(InstancePtr, 0);
			goto Func_Exit7;
		}
		break;

#ifdef HID_DEVICES
	case HID_DESC:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Get HID descriptor \r\n");
#endif
		Ch9_CmdBuf.ContWritePtr = (unsigned char *)&HidDescriptor;
		Ch9_CmdBuf.ContWriteCount =
			HidDescriptor.bLength;
		if (Ch9_CmdBuf.ContWriteCount >
		    Ch9_CmdBuf.Word3.wLength) {
			Ch9_CmdBuf.ContWriteCount =
				Ch9_CmdBuf.Word3.wLength;
		}
		break;
	case REPORT_DESC:
#ifdef 	XUSB_CH9_DEBUG
		xil_printf(" Get Report descriptor \r\n");
#endif
		Ch9_CmdBuf.ContWritePtr = (unsigned char *) &ReportDesc[0];
		Ch9_CmdBuf.ContWriteCount = sizeof (ReportDesc);
		if (Ch9_CmdBuf.ContWriteCount >
		    Ch9_CmdBuf.Word3.wLength) {
			Ch9_CmdBuf.ContWriteCount =
				Ch9_CmdBuf.Word3.wLength;
		}
		break;
#endif
	default:
		/*
		 * The default is to stall the end point zero.
		 */
		XUsb_EpStall(InstancePtr, 0);
		goto Func_Exit7;
		break;

	}
	LoadEP0(InstancePtr);

      Func_Exit7:
	return;
}

/******************************************************************************/
/**
* This routine is called when a SET_DESCRIPTOR command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note		None.
*
******************************************************************************/
void SetDescriptor(XUsb * InstancePtr)
{
	/*
	 * Command not supported.
	 */
	XUsb_EpStall(InstancePtr, 0);
}

/******************************************************************************/
/**
* This routine is called when a GET_CONFIGURATION command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note		None.
*
******************************************************************************/
void GetConfiguration(XUsb * InstancePtr)
{
	u32 *RamBase;

	UsbMemData.Word = 0x00;
	RamBase = (u32 *) (InstancePtr->Config.BaseAddress +
			   ((InstancePtr->DeviceConfig.Ep[0].RamBase) << 2));
	UsbMemData.Byte.Zero = InstancePtr->DeviceConfig.CurrentConfiguration;
	UsbMemData.Byte.One = 0;
	UsbMemData.Byte.Two = 0;
	UsbMemData.Byte.Three = 0;

	*RamBase = UsbMemData.Word;

	InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;
	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			(InstancePtr->EndPointOffset[0] +
			XUSB_EP_BUF0COUNT_OFFSET), 1);
	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
			XUSB_BUFFREADY_OFFSET, 1);
	Ch9_CmdBuf.ContWriteCount = 0;

}

/******************************************************************************/
/**
* This routine is called when a SET_CONFIGURATION command is received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note		None.
*
******************************************************************************/
void SetConfiguration(XUsb * InstancePtr)
{
	u8 Index;

#ifdef __LITTLE_ENDIAN__
	Ch9_CmdBuf.Word1.wValue =
		((u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) |
		(u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorType	<< 8));
#endif

	switch (Ch9_CmdBuf.Word1.wValue) {
	case 0:
		/*
		 * This configuration value resets the device to the
		 * un configured state like power up.
		 */
#ifdef	XUSB_CH9_DEBUG
		xil_printf("Reset Configuration \r\n");
#endif
		InstancePtr->DeviceConfig.CurrentConfiguration = 0;
		InitUsbInterface(InstancePtr);
		/*
		 * Cause a valid status phase to be issued.
		 */
		SetupControlWriteStatusStage(InstancePtr);
		break;

	case CONFIGURATION_ONE:
#ifdef	XUSB_CH9_DEBUG
		xil_printf("USB enumerated \r\n");
#endif
		InstancePtr->DeviceConfig.CurrentConfiguration = 1;


		SetupControlWriteStatusStage(InstancePtr);

		for (Index = 0; Index < InstancePtr->DeviceConfig.NumEndpoints;
		Index++){

			if (Index != 0){
				if (InstancePtr->DeviceConfig.Ep[Index].OutIn ==
						XUSB_EP_DIRECTION_OUT) {
					XUsb_WriteReg(InstancePtr->Config.BaseAddress,
						       XUSB_BUFFREADY_OFFSET, 1 << Index);

					InstancePtr->DeviceConfig.Ep[Index].Buffer0Ready = 1;

					XUsb_WriteReg(InstancePtr->Config.BaseAddress,
						       XUSB_BUFFREADY_OFFSET, (1 <<
								       (Index +
										XUSB_STATUS_EP_BUFF2_SHIFT)));
					InstancePtr->DeviceConfig.Ep[Index].Buffer1Ready = 1;
				}
			}
		}
		break;

		/*
		 * Additional configurations can be added here.
		 */
	default:
		/*
		 * stall the end point.
		 */
		XUsb_EpStall(InstancePtr, 0);
		break;
	}
}

/******************************************************************************/
/**
* This routine is called when a SET_FEATURE or a CLEAR_FEATURE command is
* received.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
* @param	flag specifies whether it is a SET_FEATURE (TRUE)or a
*		CLEAR_FEATURE (FALSE) command.
*
* @return	None.
*
* @note 	None.
*
******************************************************************************/
void SetClearFeature(XUsb * InstancePtr, int flag)
{
	u8 EndPoint;
	u8 OutInbit;
	u32 EpCfgReg;

#ifdef __LITTLE_ENDIAN__
	Ch9_CmdBuf.Word1.wValue =
		((u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorIndex) |
		(u16)(Ch9_CmdBuf.Word1.Byte23.bDescriptorType	<< 8));
#endif

	switch (Ch9_CmdBuf.Byte0.bmRequestType) {
	case STANDARD_OUT_DEVICE:
		switch (Ch9_CmdBuf.Word1.wValue) {
		case DEVICE_REMOTE_WAKEUP:
			/*
			 * User needs to add code here.
			 */
			break;

		case TEST_MODE:
			/*
			 * The Test Mode will be executed
			 * after the status phase.
			 */
			break;

		default:
			XUsb_EpStall(InstancePtr, 0);
			break;
		}
		break;

	case STANDARD_OUT_ENDPOINT:
		if (Ch9_CmdBuf.Word1.wValue == 0) {
			EndPoint = Ch9_CmdBuf.Word2.wIndex & 0xf;
			OutInbit = Ch9_CmdBuf.Word2.wIndex & 0x80;
			OutInbit = OutInbit >> 7;

			/*
			 * Make sure direction matches.
			 */
			if (OutInbit !=
			    InstancePtr->DeviceConfig.Ep[EndPoint].OutIn) {
				XUsb_EpStall(InstancePtr, 0);
				goto Func_Exit10;
			}

			if (EndPoint == 0) {
				/*
				 * Clear the stall.
				 */
				XUsb_EpUnstall(InstancePtr, 0);

				break;
			}
			else {
				if (flag == TRUE) {
					XUsb_EpStall(InstancePtr, EndPoint);
				}
				else {
					XUsb_EpUnstall(InstancePtr, EndPoint);

					/*
					 * Clear the data toggle.
					 */
					EpCfgReg =
						XUsb_ReadReg(InstancePtr->
							      Config.
							      BaseAddress,
							      InstancePtr->
							      EndPointOffset
							      [EndPoint]);
					EpCfgReg &=
						~XUSB_EP_CFG_DATA_TOGGLE_MASK;
					XUsb_WriteReg(InstancePtr->Config.
						       BaseAddress,
						       InstancePtr->
						       EndPointOffset[EndPoint],
						       EpCfgReg);
				}
			}
		}
		break;

		/*
		 * Add more here as needed.
		 */
	default:
		XUsb_EpStall(InstancePtr, 0);
		goto Func_Exit10;
		break;
	}

	/*
	 * Cause and valid status phase to be issued.
	 */
	SetupControlWriteStatusStage(InstancePtr);

      Func_Exit10:
	return;
}

/******************************************************************************/
/**
* This routine copies the EP0 related data to the DPRAM.
*
* @param	InstancePtr is a pointer to the XUsb instance of the controller.
*
* @return 	None.
*
* @note		None.
*
******************************************************************************/
void LoadEP0(XUsb * InstancePtr)
{
	u16 Count;
	u8 *RamBase;
	u16 Index;

	if (MaxControlSize >= Ch9_CmdBuf.ContWriteCount) {
		Count = Ch9_CmdBuf.ContWriteCount;
	}
	else {
		Count = MaxControlSize;
	}

	/*
	 * Copy the data to be transmitted into the DPRAM.
	 */
	RamBase = (u8 *) (InstancePtr->Config.BaseAddress +
			  ((InstancePtr->DeviceConfig.Ep[0].RamBase) << 2));
	for (Index = 0; Index < Count; Index++) {

		*RamBase++ = *Ch9_CmdBuf.ContWritePtr++;
	}

	/*
	 * Set the Tx packet size and enable the Transmission.
	 */
	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
		       XUSB_EP_BUF0COUNT_OFFSET, Count);

	XUsb_WriteReg(InstancePtr->Config.BaseAddress,
		       XUSB_BUFFREADY_OFFSET, 1);

	InstancePtr->DeviceConfig.Ep[0].Buffer0Ready = 1;

	Ch9_CmdBuf.ContWriteCount -= Count;
}