//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

#include <windows.h>
#include <halether.h>
#include <s2440.h>
// #include <S3C2440EVBD.h>
#include "loader.h"
#include <drv_glob.h>

#define USB_BASE	0xB1200140
volatile struct udcreg 	* pUSBCtrlAddr;
int g_DMAbufIndex = 0;
int debugM = 0;
volatile int DMADone = 0;

#define REAL_PHYSICAL_ADDR_EP3_FIFO		(0x520001CC) //Endpoint 3 FIFO
ULONG realPhysicalAddr_UsbdRxBuf=0;

//OUT_CSR2
#define EPO_OUT_DMA_INT_MASK	(1<<5)
#define EPO_ISO		 	(1<<6)
#define EPO_BULK	 	(0<<6)
#define EPO_AUTO_CLR		(1<<7)

//USB DMA control register
#define UDMA_IN_RUN_OB		(1<<7)
#define UDMA_IGNORE_TTC		(1<<7)
#define UDMA_DEMAND_MODE	(1<<3)
#define UDMA_OUT_RUN_OB		(1<<2)
#define UDMA_OUT_DMA_RUN	(1<<2)
#define UDMA_IN_DMA_RUN		(1<<1)
#define UDMA_DMA_MODE_EN	(1<<0)

#define pISR		(*(unsigned *)(0x30000000+0x18))		// Virtual Address 0x0 is mapped to 0x30000000, ISR Address is VA 0x18
#define U8	unsigned char
#define U32 unsigned int
#define BUFARRAYSIZE 64
volatile unsigned char downArr[BUFARRAYSIZE];
volatile unsigned char *downPt;

#define DMABUFFER 0x32000000
volatile unsigned int downPtIndex = DMABUFFER;
volatile unsigned int readPtIndex = DMABUFFER;
#define BULK_PKT_SIZE			64
#define EP0_PKT_SIZE			8	
#define EP1_PKT_SIZE			BULK_PKT_SIZE
#define EP3_PKT_SIZE			BULK_PKT_SIZE
U8 ep1Buf[EP1_PKT_SIZE];
int transferIndex=0;
void Isr_Init(void);
void IsrUsbd(unsigned int val);
void IsrHandler(void);
void Ep3Handler(void);
void ConfigEp3DmaMode(U32 bufAddr,U32 count);
void DMA2Handler(void);

#define rEP3_DMA_TTC_L     (*(volatile unsigned char *)0x5200024c)	//EP3 DMA total Tx counter
#define rEP3_DMA_TTC_M     (*(volatile unsigned char *)0x52000250)
#define rEP3_DMA_TTC_H     (*(volatile unsigned char *)0x52000254)
#define rEP3_DMA_TTC	(pUSBCtrlAddr->EP3DTL.ep3_ttl_l+(pUSBCtrlAddr->EP3DTM.ep3_ttl_m<<8)+(pUSBCtrlAddr->EP3DTH.ep3_ttl_h<<16))

#define SKIP 1
#define DOIT 0

// Standard bmRequestType (Recipient)
#define DEVICE_RECIPIENT            (0)
#define INTERFACE_RECIPIENT         (1)
#define ENDPOINT_RECIPIENT          (2)
#define OTHER_RECIPIENT             (3)

#define EP0_STATE_INIT			(0)  
#define EP0_STATE_GD_DEV_0		(10)  //10-10=0 
#define EP0_STATE_GD_DEV_1		(11)  //11-10=1
#define EP0_STATE_GD_DEV_2		(12)  //12-10=2
#define EP0_STATE_GD_CFG_0		(20)
#define EP0_STATE_GD_CFG_1		(21)
#define EP0_STATE_GD_CFG_2		(22)
#define EP0_STATE_GD_CFG_3		(23)
#define EP0_STATE_GD_CFG_4		(24)
#define EP0_STATE_GD_CFG_ONLY_0	(40)
#define EP0_STATE_GD_CFG_ONLY_1	(41)
#define EP0_STATE_GD_IF_ONLY_0	(42)
#define EP0_STATE_GD_IF_ONLY_1	(43)
#define EP0_STATE_GD_EP0_ONLY_0	(44)
#define EP0_STATE_GD_EP1_ONLY_0	(45)
#define EP0_INTERFACE_GET		(46)
#define EP0_STATE_GD_STR_I0		(30)  
#define EP0_STATE_GD_STR_I1		(31)  
#define EP0_STATE_GD_STR_I2		(32)  
#define EP0_CONFIG_SET			(33)
#define EP0_GET_STATUS0			(35)
#define EP0_GET_STATUS1			(36)
#define EP0_GET_STATUS2			(37)
#define EP0_GET_STATUS3			(38)
#define EP0_GET_STATUS4			(39)

#define CLR_EP0_OUT_PKT_RDY()		pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1; pUSBCtrlAddr->EP0ICSR1.sse_ = 0;
#define CLR_EP0_OUTPKTRDY_DATAEND() pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1; pUSBCtrlAddr->EP0ICSR1.de_ff = 1;; pUSBCtrlAddr->EP0ICSR1.sse_ = 0;
#define SET_EP0_IN_PKT_RDY() 		pUSBCtrlAddr->EP0ICSR1.ipr_ = 1; pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 0; pUSBCtrlAddr->EP0ICSR1.sse_ = 0;

#define SET_EP0_INPKTRDY_DATAEND() 	pUSBCtrlAddr->EP0ICSR1.ipr_ = 1; pUSBCtrlAddr->EP0ICSR1.de_ff = 1; pUSBCtrlAddr->EP0ICSR1.sse_ = 0; pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 0;
#define CLR_EP0_SETUP_END() 		pUSBCtrlAddr->EP0ICSR1.sse_ = 1; pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 0;
#define CLR_EP0_SENT_STALL() 		pUSBCtrlAddr->EP0ICSR1.sts_ur = 0; pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 0; pUSBCtrlAddr->EP0ICSR1.sse_ = 0;
#define FLUSH_EP0_FIFO() 			{while(pUSBCtrlAddr->OFCR1.out_cnt_low) pUSBCtrlAddr->EP0F.fifo_data;}

#define CLR_EP3_OUT_PKT_READY()		pUSBCtrlAddr->OCSR1.fifo_flush = 0;	pUSBCtrlAddr->OCSR1.send_stall = 0;	pUSBCtrlAddr->OCSR1.clr_data_tog = 0; pUSBCtrlAddr->OCSR1.out_pkt_rdy = 0;
#define CLR_EP3_SENT_STALL()		pUSBCtrlAddr->OCSR1.fifo_flush = 0;	pUSBCtrlAddr->OCSR1.send_stall = 0; pUSBCtrlAddr->OCSR1.clr_data_tog = 0; pUSBCtrlAddr->OCSR1.sent_stall = 0;

volatile U8 Rwuen;
volatile U8 Selfpwr=TRUE;
U32 ep0State;

struct USB_SETUP_DATA{
	U8 bmRequestType;    
	U8 bRequest;         
	U8 bValueL;          
	U8 bValueH;          
	U8 bIndexL;          
	U8 bIndexH;          
	U8 bLengthL;         
	U8 bLengthH;         
};

struct USB_DEVICE_DESCRIPTOR{
	U8 bLength;    
	U8 bDescriptorType;         
	U8 bcdUSBL;
	U8 bcdUSBH;
	U8 bDeviceClass;
	U8 bDeviceSubClass;
	U8 bDeviceProtocol;
	U8 bMaxPacketSize0;
	U8 idVendorL;
	U8 idVendorH;
	U8 idProductL;
	U8 idProductH;
	U8 bcdDeviceL;
	U8 bcdDeviceH;
	U8 iManufacturer;
	U8 iProduct;
	U8 iSerialNumber;
	U8 bNumConfigurations;
};

struct USB_CONFIGURATION_DESCRIPTOR{
	U8 bLength;    
	U8 bDescriptorType;         
	U8 wTotalLengthL;
	U8 wTotalLengthH;
	U8 bNumInterfaces;
	U8 bConfigurationValue;
	U8 iConfiguration;
	U8 bmAttributes;
	U8 maxPower;          
};

struct USB_INTERFACE_DESCRIPTOR{
	U8 bLength;    
	U8 bDescriptorType;         
	U8 bInterfaceNumber;
	U8 bAlternateSetting;
	U8 bNumEndpoints;
	U8 bInterfaceClass;
	U8 bInterfaceSubClass;
	U8 bInterfaceProtocol;
	U8 iInterface;
};

struct USB_ENDPOINT_DESCRIPTOR{
	U8 bLength;    
	U8 bDescriptorType;         
	U8 bEndpointAddress;
	U8 bmAttributes;
	U8 wMaxPacketSizeL;
	U8 wMaxPacketSizeH;
	U8 bInterval;
};

struct USB_CONFIGURATION_SET{
	U8 ConfigurationValue;
};

struct USB_GET_STATUS{
	U8 Device;
	U8 Interface;
	U8 Endpoint0;
	U8 Endpoint1;
	U8 Endpoint3;
};

struct USB_INTERFACE_GET{
	U8 AlternateSetting;
};

struct USB_SETUP_DATA descSetup;
struct USB_DEVICE_DESCRIPTOR descDev;
struct USB_CONFIGURATION_DESCRIPTOR descConf;
struct USB_INTERFACE_DESCRIPTOR descIf;
struct USB_ENDPOINT_DESCRIPTOR descEndpt0;
struct USB_ENDPOINT_DESCRIPTOR descEndpt1;
struct USB_CONFIGURATION_SET ConfigSet;
struct USB_INTERFACE_GET InterfaceGet;
struct USB_GET_STATUS StatusGet;   //={0,0,0,0,0};

// Descriptor Types
#define USB_DEVICE_TYPE                 (1)
#define CONFIGURATION_TYPE          (2)
#define STRING_TYPE                 (3)
#define INTERFACE_TYPE              (4)
#define ENDPOINT_TYPE               (5)

//string descriptor
#define LANGID_US_L 		    (0x09)  
#define LANGID_US_H 		    (0x04)

// Standard Request Codes 
#define GET_STATUS                  (0)
#define CLEAR_FEATURE               (1)
#define SET_FEATURE                 (3)
#define SET_ADDRESS                 (5)
#define GET_DESCRIPTOR              (6)
#define SET_DESCRIPTOR              (7)
#define GET_CONFIGURATION           (8)
#define SET_CONFIGURATION           (9)
#define GET_INTERFACE               (10)
#define SET_INTERFACE               (11)
#define SYNCH_FRAME                 (12)

//configuration descriptor: bmAttributes 
#define CONF_ATTR_DEFAULT	    (0x80) //Spec 1.0 it was BUSPOWERED bit.
#define CONF_ATTR_REMOTE_WAKEUP     (0x20)
#define CONF_ATTR_SELFPOWERED       (0x40)

//endpoint descriptor
#define EP_ADDR_IN		    (0x80)	
#define EP_ADDR_OUT		    (0x00)

#define EP_ATTR_CONTROL		    (0x0)	
#define EP_ATTR_ISOCHRONOUS	    (0x1)
#define EP_ATTR_BULK		    (0x2)
#define EP_ATTR_INTERRUPT	    (0x3)	

static const U8 descStr0[]={
	4,STRING_TYPE,LANGID_US_L,LANGID_US_H,  //codes representing languages
    };

static const U8 descStr1[]={  //Manufacturer  
        (0x14+2),STRING_TYPE, 
        'S',0x0,'y',0x0,'s',0x0,'t',0x0,'e',0x0,'m',0x0,' ',0x0,'M',0x0,
        'C',0x0,'U',0x0,
    };
    
static const U8 descStr2[]={  //Product  
        (0x2a+2),STRING_TYPE, 
        'S',0x0,'E',0x0,'C',0x0,' ',0x0,'S',0x0,'3',0x0,'C',0x0,'2',0x0,
        '4',0x0,'1',0x0,'0',0x0,'X',0x0,' ',0x0,'T',0x0,'e',0x0,'s',0x0,
        't',0x0,' ',0x0,'B',0x0,'/',0x0,'D',0x0
    };

void InitDescriptorTable(void)
{	
    //Standard device descriptor
    descDev.bLength=0x12;	//EP0_DEV_DESC_SIZE=0x12 bytes    
    descDev.bDescriptorType=USB_DEVICE_TYPE;
    descDev.bcdUSBL=0x10;
    descDev.bcdUSBH=0x01; 	//Ver 1.10
    descDev.bDeviceClass=0xFF; //0x0          
    descDev.bDeviceSubClass=0x0;          
    descDev.bDeviceProtocol=0x0;          
    descDev.bMaxPacketSize0=0x8;         
    descDev.idVendorL=0x45;
    descDev.idVendorH=0x53;
    descDev.idProductL=0x34;
    descDev.idProductH=0x12;
    descDev.bcdDeviceL=0x00;
    descDev.bcdDeviceH=0x01;
    descDev.iManufacturer=0x1;  //index of string descriptor
    descDev.iProduct=0x2;	//index of string descriptor 
    descDev.iSerialNumber=0x0;
    descDev.bNumConfigurations=0x1;

    //Standard configuration descriptor
    descConf.bLength=0x9;    
    descConf.bDescriptorType=CONFIGURATION_TYPE;         
    descConf.wTotalLengthL=0x20; //<cfg desc>+<if desc>+<endp0 desc>+<endp1 desc>
    descConf.wTotalLengthH=0;
    descConf.bNumInterfaces=1;
//dbg    descConf.bConfigurationValue=2;  //why 2? There's no reason.
    descConf.bConfigurationValue=1;  
    descConf.iConfiguration=0;
    descConf.bmAttributes=CONF_ATTR_DEFAULT|CONF_ATTR_SELFPOWERED;  //bus powered only.
    descConf.maxPower=25; //draws 50mA current from the USB bus.          

    //Standard interface descriptor
    descIf.bLength=0x9;    
    descIf.bDescriptorType=INTERFACE_TYPE;         
    descIf.bInterfaceNumber=0x0;
    descIf.bAlternateSetting=0x0; //?
    descIf.bNumEndpoints=2;	//# of endpoints except EP0
    descIf.bInterfaceClass=0xff; //0x0 ?
    descIf.bInterfaceSubClass=0x0;  
    descIf.bInterfaceProtocol=0x0;
    descIf.iInterface=0x0;

    //Standard endpoint0 descriptor
    descEndpt0.bLength=0x7;    
    descEndpt0.bDescriptorType=ENDPOINT_TYPE;         
    descEndpt0.bEndpointAddress=1|EP_ADDR_IN;   // 2400Xendpoint 1 is IN endpoint.
    descEndpt0.bmAttributes=EP_ATTR_BULK;
    descEndpt0.wMaxPacketSizeL=EP1_PKT_SIZE; //64
    descEndpt0.wMaxPacketSizeH=0x0;
    descEndpt0.bInterval=0x0; //not used

    //Standard endpoint1 descriptor
    descEndpt1.bLength=0x7;    
    descEndpt1.bDescriptorType=ENDPOINT_TYPE;         
    descEndpt1.bEndpointAddress=3|EP_ADDR_OUT;   // 2400X endpoint 3 is OUT endpoint.
    descEndpt1.bmAttributes=EP_ATTR_BULK;
    descEndpt1.wMaxPacketSizeL=EP3_PKT_SIZE; //64
    descEndpt1.wMaxPacketSizeH=0x0;
    descEndpt1.bInterval=0x0; //not used 
}

BOOL InitUSB()
{
	BYTE index;
	UCHAR cRxChar;

	volatile INTreg *s2440INT = (INTreg *)INT_BASE;
	pUSBCtrlAddr = (PUSHORT)(USB_BASE);

    InitDescriptorTable();

    //
    // Initialize the USBD Controller
    //
    index = pUSBCtrlAddr->INDEX.index;

    // suspend mode disable
    pUSBCtrlAddr->PMR.sus_en = 0x0;

    // setup endpoint 0
    pUSBCtrlAddr->INDEX.index = 0;
    pUSBCtrlAddr->MAXP.maxp = 0x1;         // 8 BYTE
    pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;   // OUT_PKT_RDY
    pUSBCtrlAddr->EP0ICSR1.sse_ = 1;       // SETUP_END

    // setup endpoint 1
    pUSBCtrlAddr->INDEX.index = 1;
    pUSBCtrlAddr->MAXP.maxp = 0x8;     // 64 BYTE
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
    pUSBCtrlAddr->ICSR2.mode_in = 1;   // IN
    pUSBCtrlAddr->ICSR2.iso = 0;       // BULK

    // setup endpoint 3
    pUSBCtrlAddr->INDEX.index = 3;
    pUSBCtrlAddr->MAXP.maxp = 0x8;     // 64 BYTE
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
    pUSBCtrlAddr->ICSR2.mode_in = 0;   // OUT
    pUSBCtrlAddr->OCSR2.iso = 0;       // BULK

    // clear all EP interrupts
    pUSBCtrlAddr->EIR.ep0_int = 0x1;
    pUSBCtrlAddr->EIR.ep1_int = 0x1;
    pUSBCtrlAddr->EIR.ep2_int = 0x1;
    pUSBCtrlAddr->EIR.ep3_int = 0x1;
    pUSBCtrlAddr->EIR.ep4_int = 0x1;

    // clear reset int
    pUSBCtrlAddr->UIR.reset_int = 0x1;

    // EP0, 1, & 3 Enabled, EP2, 4 Disabled
    pUSBCtrlAddr->EIER.ep0_int_en = 0x1;
    pUSBCtrlAddr->EIER.ep2_int_en = 0x0;
    pUSBCtrlAddr->EIER.ep4_int_en = 0x0;
    pUSBCtrlAddr->EIER.ep1_int_en = 0x1;
    pUSBCtrlAddr->EIER.ep3_int_en = 0x1;

    // enable reset int 
    pUSBCtrlAddr->UIER.reset_int_en = 0x1;

	return TRUE;
}

void PrintEp0Pkt(U8 *pt)
{
    int i;
	EdbgOutputDebugString("[RCV:");
	for(i=0;i<EP0_PKT_SIZE;i++)
		EdbgOutputDebugString("%x,",pt[i]);
	EdbgOutputDebugString("]\r\n");
}

void WrPktEp0(U8 *buf,int num)
{
	int i;
    
	for(i=0;i<num;i++)
	{
		pUSBCtrlAddr->EP0F.fifo_data = buf[i];
	}
}

void WrPktEp1(U8 *buf,int num)
{
    int i;
    	
    for(i=0;i<num;i++)
    {
        pUSBCtrlAddr->EP1F.fifo_data = buf[i];
    }
}

void RdPktEp0(U8 *buf,int num)
{
    int i;
    	
    for(i=0;i<num;i++)
    {
        buf[i]=(U8)pUSBCtrlAddr->EP0F.fifo_data;	
    }
}

void RdPktEp3(U8 *buf,int num)
{
	int i;

	for(i=0;i<num;i++)
	{
		buf[i]=(U8)(pUSBCtrlAddr->EP3F.fifo_data);
    }
}

void PrepareEp1Fifo(void) 
{
    int i;
    pUSBCtrlAddr->INDEX.index=1;
    
    for(i=0;i<EP1_PKT_SIZE;i++)ep1Buf[i]=(U8)(transferIndex+i);
    WrPktEp1(ep1Buf,EP1_PKT_SIZE);
	pUSBCtrlAddr->EP0ICSR1.opr_ipr = 1;
	pUSBCtrlAddr->EP0ICSR1.sts_ur = 0;
	pUSBCtrlAddr->EP0ICSR1.de_ff = 0;
}

void Ep1Handler(void)
{
    pUSBCtrlAddr->INDEX.index=1;
    
    if(pUSBCtrlAddr->EP0ICSR1.sds_sts)
    {   
		pUSBCtrlAddr->EP0ICSR1.opr_ipr = 0;
		pUSBCtrlAddr->EP0ICSR1.sts_ur = 0;
		pUSBCtrlAddr->EP0ICSR1.de_ff = 0;
		pUSBCtrlAddr->EP0ICSR1.sds_sts = 0;
   		return;
    }	

    transferIndex++;

    PrepareEp1Fifo(); 

    return;
}

void Ep0Handler(void)
{
	static int ep0SubState;

	pUSBCtrlAddr->INDEX.index=0;

	//DATAEND interrupt(ep0_csr==0x0) will be ignored 
	//because ep0State==EP0_STATE_INIT when the DATAEND interrupt is issued.

//	EdbgOutputDebugString("INFO : Ep0Handler\r\n");

	if(pUSBCtrlAddr->EP0ICSR1.se_sds)
	{   
		// Host may end GET_DESCRIPTOR operation without completing the IN data stage.
		// If host does that, SETUP_END bit will be set.
		// OUT_PKT_RDY has to be also cleared because status stage sets OUT_PKT_RDY to 1.
		CLR_EP0_SETUP_END();
		if(pUSBCtrlAddr->EP0ICSR1.opr_ipr) 
		{
			FLUSH_EP0_FIFO(); //(???)
			//I think this isn't needed because EP0 flush is done automatically.   
			CLR_EP0_OUT_PKT_RDY();
		}

		ep0State=EP0_STATE_INIT;
		return;
	}	

	//I think that EP0_SENT_STALL will not be set to 1.
	if(pUSBCtrlAddr->EP0ICSR1.sts_ur)
	{   
		EdbgOutputDebugString("[STALL]\r\n");
		CLR_EP0_SENT_STALL();
		if(pUSBCtrlAddr->EP0ICSR1.opr_ipr)
		{
			CLR_EP0_OUT_PKT_RDY();
		}

		ep0State=EP0_STATE_INIT;
		return;
	}	

	if((pUSBCtrlAddr->EP0ICSR1.opr_ipr) && (ep0State==EP0_STATE_INIT))
	{
		RdPktEp0((U8 *)&descSetup,EP0_PKT_SIZE);

		switch(descSetup.bRequest)
		{
		case GET_DESCRIPTOR:
			switch(descSetup.bValueH)        
			{
            case USB_DEVICE_TYPE:
				CLR_EP0_OUT_PKT_RDY();
				ep0State=EP0_STATE_GD_DEV_0;	        
				break;	
			case CONFIGURATION_TYPE:
				CLR_EP0_OUT_PKT_RDY();
				if((descSetup.bLengthL+(descSetup.bLengthH<<8))>0x9)
					//bLengthH should be used for bLength=0x209 at WIN2K.    	
					ep0State=EP0_STATE_GD_CFG_0; //for WIN98,WIN2K
				else	    	    
					ep0State=EP0_STATE_GD_CFG_ONLY_0; //for WIN2K
				break;
			case STRING_TYPE:
				CLR_EP0_OUT_PKT_RDY();
				switch(descSetup.bValueL)
				{
				case 0:
					ep0State=EP0_STATE_GD_STR_I0;
					break;
				case 1:
					ep0State=EP0_STATE_GD_STR_I1;
					break;
				case 2:	
					ep0State=EP0_STATE_GD_STR_I2;
					break;
				default:
					EdbgOutputDebugString("[UE:STRI?]\r\n");
					break;
				}
				ep0SubState=0;
				break;
			case INTERFACE_TYPE:
				EdbgOutputDebugString("[GDI]\r\n");
				CLR_EP0_OUT_PKT_RDY();
				ep0State=EP0_STATE_GD_IF_ONLY_0; //for WIN98
				break;
			case ENDPOINT_TYPE:	    	
				EdbgOutputDebugString("[GDE]\r\n");
				CLR_EP0_OUT_PKT_RDY();
				switch(descSetup.bValueL&0xf)
				{
				case 0:
					ep0State=EP0_STATE_GD_EP0_ONLY_0;
					break;
				case 1:
					ep0State=EP0_STATE_GD_EP1_ONLY_0;
					break;
				default:
					EdbgOutputDebugString("[UE:GDE?]\r\n");
					break;
				}
				break;
			default:
				EdbgOutputDebugString("[UE:GD?]\r\n");
				break;
			}
			break;

		case SET_ADDRESS:
			pUSBCtrlAddr->udcFAR.func_addr = descSetup.bValueL;
			pUSBCtrlAddr->udcFAR.addr_up = 1;
			CLR_EP0_OUTPKTRDY_DATAEND(); //Because of no data control transfers.
			ep0State=EP0_STATE_INIT;
			break;
    	
		case SET_CONFIGURATION:
			ConfigSet.ConfigurationValue=descSetup.bValueL;
			CLR_EP0_OUTPKTRDY_DATAEND(); //Because of no data control transfers.
			ep0State=EP0_STATE_INIT;

			break;

			//////////////////////// For chapter 9 test ////////////////////

		case CLEAR_FEATURE:
			switch (descSetup.bmRequestType)
			{
			case DEVICE_RECIPIENT:
				if (descSetup.bValueL == 1)
					Rwuen = FALSE;
				break;

			case ENDPOINT_RECIPIENT:
				if (descSetup.bValueL == 0)
				{
					if((descSetup.bIndexL & 0x7f) == 0x00){
						StatusGet.Endpoint0= 0;    
					}
					if((descSetup.bIndexL & 0x8f) == 0x81){           // IN  Endpoint 1
						StatusGet.Endpoint1= 0;           
					}
					if((descSetup.bIndexL & 0x8f) == 0x03){          // OUT Endpoint 3
						StatusGet.Endpoint3= 0;      
					}
				}
				break;

			default:
				break;
			}
			CLR_EP0_OUTPKTRDY_DATAEND();
			ep0State=EP0_STATE_INIT;
			break;

		case GET_CONFIGURATION:
			CLR_EP0_OUT_PKT_RDY();
			ep0State=EP0_CONFIG_SET;
			break;

		case GET_INTERFACE:
			CLR_EP0_OUT_PKT_RDY();
			ep0State=EP0_INTERFACE_GET;
			break;

		case GET_STATUS:
			switch(descSetup.bmRequestType)
			{
			case  (0x80):
				CLR_EP0_OUT_PKT_RDY();
				StatusGet.Device=((U8)Rwuen<<1)|(U8)Selfpwr;
				ep0State=EP0_GET_STATUS0;
				break;

			case  (0x81):
				CLR_EP0_OUT_PKT_RDY();
				StatusGet.Interface=0;
				ep0State=EP0_GET_STATUS1;
				break;

			case  (0x82):
				CLR_EP0_OUT_PKT_RDY();
				if((descSetup.bIndexL & 0x7f) == 0x00){
					ep0State=EP0_GET_STATUS2;
				}
				if((descSetup.bIndexL & 0x8f) == 0x81){
					ep0State=EP0_GET_STATUS3;
				}
				if((descSetup.bIndexL & 0x8f) == 0x03){
					ep0State=EP0_GET_STATUS4;
				}
				break;

			default:
				break;
    	  	}
    	  	break;

		case SET_DESCRIPTOR:
			CLR_EP0_OUTPKTRDY_DATAEND();
			ep0State=EP0_STATE_INIT;
			break;

		case SET_FEATURE:
			switch (descSetup.bmRequestType)
			{
			case DEVICE_RECIPIENT:
				if (descSetup.bValueL == 1)
					Rwuen = TRUE;
				break;

			case ENDPOINT_RECIPIENT:
				if (descSetup.bValueL == 0)
				{
					if((descSetup.bIndexL & 0x7f) == 0x00){
						StatusGet.Endpoint0= 1;
					}
					if((descSetup.bIndexL & 0x8f) == 0x81){
						StatusGet.Endpoint1= 1;
					}
					if((descSetup.bIndexL & 0x8f) == 0x03){
						StatusGet.Endpoint3= 1;
					}
				}
				break;
			default:
			break;
			}
			CLR_EP0_OUTPKTRDY_DATAEND();
			ep0State=EP0_STATE_INIT;
			break;

		case SET_INTERFACE:
			InterfaceGet.AlternateSetting= descSetup.bValueL;
			CLR_EP0_OUTPKTRDY_DATAEND(); 
			ep0State=EP0_STATE_INIT;
			break;

		case SYNCH_FRAME:
			ep0State=EP0_STATE_INIT;
			break;

    	  //////////////////////////////////////////////////////////////

		default:
			EdbgOutputDebugString("[UE:SETUP=%x]\r\n",descSetup.bRequest);
			CLR_EP0_OUTPKTRDY_DATAEND(); //Because of no data control transfers.
			ep0State=EP0_STATE_INIT;
			break;
		}
	}

	switch(ep0State)
	{
	case EP0_STATE_INIT:
		break; 

	//=== GET_DESCRIPTOR:DEVICE ===
	case EP0_STATE_GD_DEV_0:
		WrPktEp0((U8 *)&descDev+0,8); //EP0_PKT_SIZE
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_DEV_1;
		break;

	case EP0_STATE_GD_DEV_1:
		WrPktEp0((U8 *)&descDev+0x8,8); 
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_DEV_2;
		break;

	case EP0_STATE_GD_DEV_2:
		WrPktEp0((U8 *)&descDev+0x10,2);   //8+8+2=0x12
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;
		break;

	//=== GET_DESCRIPTOR:CONFIGURATION+INTERFACE+ENDPOINT0+ENDPOINT1 ===
	//Windows98 gets these 4 descriptors all together by issuing only a request.
	//Windows2000 gets each descriptor seperately.
	case EP0_STATE_GD_CFG_0:
		WrPktEp0((U8 *)&descConf+0,8); //EP0_PKT_SIZE
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_CFG_1;
		break;

	case EP0_STATE_GD_CFG_1:
		WrPktEp0((U8 *)&descConf+8,1); 
		WrPktEp0((U8 *)&descIf+0,7); 
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_CFG_2;
		break;

	case EP0_STATE_GD_CFG_2:
		WrPktEp0((U8 *)&descIf+7,2); 
		WrPktEp0((U8 *)&descEndpt0+0,6); 
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_CFG_3;
		break;

	case EP0_STATE_GD_CFG_3:
		WrPktEp0((U8 *)&descEndpt0+6,1); 
		WrPktEp0((U8 *)&descEndpt1+0,7); 
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_CFG_4;            
		break;

	case EP0_STATE_GD_CFG_4:
		 //zero length data packit 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;            
		break;

	//=== GET_DESCRIPTOR:CONFIGURATION ONLY===
	case EP0_STATE_GD_CFG_ONLY_0:
		WrPktEp0((U8 *)&descConf+0,8); //EP0_PKT_SIZE
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_CFG_ONLY_1;
		break;
    
	case EP0_STATE_GD_CFG_ONLY_1:
		WrPktEp0((U8 *)&descConf+8,1); 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;            
		break;

	//=== GET_DESCRIPTOR:INTERFACE ONLY===
	case EP0_STATE_GD_IF_ONLY_0:
		EdbgOutputDebugString("[GDI0]\r\n");
		WrPktEp0((U8 *)&descIf+0,8); 
		SET_EP0_IN_PKT_RDY();
		ep0State=EP0_STATE_GD_IF_ONLY_1;
		break;

	case EP0_STATE_GD_IF_ONLY_1:
		EdbgOutputDebugString("[GDI1]\r\n");
		WrPktEp0((U8 *)&descIf+8,1); 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;            
		break;

	//=== GET_DESCRIPTOR:ENDPOINT 0 ONLY===
	case EP0_STATE_GD_EP0_ONLY_0:
		EdbgOutputDebugString("[GDE00]\r\n");
		WrPktEp0((U8 *)&descEndpt0+0,7); 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;            
		break;
            
	//=== GET_DESCRIPTOR:ENDPOINT 1 ONLY===
	case EP0_STATE_GD_EP1_ONLY_0:
		EdbgOutputDebugString("[GDE10]\r\n");
		WrPktEp0((U8 *)&descEndpt1+0,7); 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;            
		break;
            
////////////////////////////////////////////

	case EP0_INTERFACE_GET:
		WrPktEp0((U8 *)&InterfaceGet+0,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

 
	//=== GET_DESCRIPTOR:STRING ===
	case EP0_STATE_GD_STR_I0:
		WrPktEp0((U8 *)descStr0, 4 );  
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;     
		ep0SubState=0;
		break;

	case EP0_STATE_GD_STR_I1:
		if( (ep0SubState*EP0_PKT_SIZE+EP0_PKT_SIZE)<sizeof(descStr1) )
		{
			WrPktEp0((U8 *)descStr1+(ep0SubState*EP0_PKT_SIZE),EP0_PKT_SIZE); 
			SET_EP0_IN_PKT_RDY();
			ep0State=EP0_STATE_GD_STR_I1;
			ep0SubState++;
		}
		else
		{
			WrPktEp0((U8 *)descStr1+(ep0SubState*EP0_PKT_SIZE),
			sizeof(descStr1)-(ep0SubState*EP0_PKT_SIZE)); 
			SET_EP0_INPKTRDY_DATAEND();
			ep0State=EP0_STATE_INIT;     
			ep0SubState=0;
		}
		break;

	case EP0_STATE_GD_STR_I2:
		if( (ep0SubState*EP0_PKT_SIZE+EP0_PKT_SIZE)<sizeof(descStr2) )
		{
			WrPktEp0((U8 *)descStr2+(ep0SubState*EP0_PKT_SIZE),EP0_PKT_SIZE); 
			SET_EP0_IN_PKT_RDY();
			ep0State=EP0_STATE_GD_STR_I2;
			ep0SubState++;
		}
		else
		{
			WrPktEp0((U8 *)descStr2+(ep0SubState*EP0_PKT_SIZE),
			sizeof(descStr2)-(ep0SubState*EP0_PKT_SIZE)); 
			SET_EP0_INPKTRDY_DATAEND();
			ep0State=EP0_STATE_INIT;     
			ep0SubState=0;
		}
		break;

	case EP0_CONFIG_SET:
		WrPktEp0((U8 *)&ConfigSet+0,1); 
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	case EP0_GET_STATUS0:
		WrPktEp0((U8 *)&StatusGet+0,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	case EP0_GET_STATUS1:
		WrPktEp0((U8 *)&StatusGet+1,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	case EP0_GET_STATUS2:
		WrPktEp0((U8 *)&StatusGet+2,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	case EP0_GET_STATUS3:
		WrPktEp0((U8 *)&StatusGet+3,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	case EP0_GET_STATUS4:
		WrPktEp0((U8 *)&StatusGet+4,1);
		SET_EP0_INPKTRDY_DATAEND();
		ep0State=EP0_STATE_INIT;      
		break;

	default:
//		DbgPrintf("UE:G?D");
		EdbgOutputDebugString("[UE:G?D]\r\n");
		break;
	}
}

void ReconfigUsbd(void)
{
// *** End point information ***
//   EP0: control
//   EP1: bulk in end point
//   EP2: not used
//   EP3: bulk out end point
//   EP4: not used
    
	pUSBCtrlAddr->PMR.sus_en = 0;
	pUSBCtrlAddr->PMR.sus_mo = 0;
	pUSBCtrlAddr->PMR.muc_res = 0;
	pUSBCtrlAddr->PMR.usb_re = 0;
	pUSBCtrlAddr->PMR.iso_up = 0;

	pUSBCtrlAddr->INDEX.index = 0;
	pUSBCtrlAddr->MAXP.maxp = 0x01;	//EP0 max packit size = 8 
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
	pUSBCtrlAddr->EP0ICSR1.sse_ = 1;
	//EP0:clear OUT_PKT_RDY & SETUP_END

	pUSBCtrlAddr->INDEX.index = 1;
	pUSBCtrlAddr->MAXP.maxp = 0x08;	//EP1 max packit size = 64 
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
	pUSBCtrlAddr->ICSR2.mode_in = 1;
	pUSBCtrlAddr->ICSR2.in_dma_int_en = 1;
	pUSBCtrlAddr->ICSR2.iso = 0;
	pUSBCtrlAddr->OCSR1.clr_data_tog = 1;
	pUSBCtrlAddr->OCSR2.iso = 0;
	pUSBCtrlAddr->OCSR2.out_dma_int_en = 1;

	pUSBCtrlAddr->INDEX.index = 2;
	pUSBCtrlAddr->MAXP.maxp = 0x08;	//EP2 max packit size = 64 
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
	pUSBCtrlAddr->ICSR2.mode_in = 1;
	pUSBCtrlAddr->ICSR2.in_dma_int_en = 1;
	pUSBCtrlAddr->ICSR2.iso = 0;
	pUSBCtrlAddr->OCSR1.clr_data_tog = 1;
	pUSBCtrlAddr->OCSR2.iso = 0;
	pUSBCtrlAddr->OCSR2.out_dma_int_en = 1;

	pUSBCtrlAddr->INDEX.index = 3;
	pUSBCtrlAddr->MAXP.maxp = 0x08;	//EP3 max packit size = 64 
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
	pUSBCtrlAddr->ICSR2.mode_in = 0;
	pUSBCtrlAddr->ICSR2.in_dma_int_en = 0;
	pUSBCtrlAddr->ICSR2.iso = 0;
	pUSBCtrlAddr->OCSR1.clr_data_tog = 1;
	//clear OUT_PKT_RDY, data_toggle_bit.
	//The data toggle bit should be cleared when initialization.
	pUSBCtrlAddr->OCSR2.iso = 0;
	pUSBCtrlAddr->OCSR2.out_dma_int_en = 1;

	pUSBCtrlAddr->INDEX.index = 4;
	pUSBCtrlAddr->MAXP.maxp = 0x08;	//EP4 max packit size = 64 
	pUSBCtrlAddr->EP0ICSR1.de_ff = 1;
	pUSBCtrlAddr->EP0ICSR1.sopr_cdt = 1;
	pUSBCtrlAddr->ICSR2.mode_in = 0;
	pUSBCtrlAddr->ICSR2.in_dma_int_en = 1;
	pUSBCtrlAddr->ICSR2.iso = 0;
	pUSBCtrlAddr->OCSR1.clr_data_tog = 1;
	//clear OUT_PKT_RDY, data_toggle_bit.
	//The data toggle bit should be cleared when initialization.
	pUSBCtrlAddr->OCSR2.iso = 0;
	pUSBCtrlAddr->OCSR2.out_dma_int_en = 1;

	pUSBCtrlAddr->EIR.ep0_int=1;
	pUSBCtrlAddr->EIR.ep1_int=1;
	pUSBCtrlAddr->EIR.ep2_int=1;
	pUSBCtrlAddr->EIR.ep3_int=1;
	pUSBCtrlAddr->EIR.ep4_int=1;
	pUSBCtrlAddr->UIR.reset_int = 1;
	pUSBCtrlAddr->UIR.sus_int = 1;
	pUSBCtrlAddr->UIR.resume_int = 1;

	//Clear all usbd pending bits

	//EP0,1,3 & reset interrupt are enabled
	pUSBCtrlAddr->EIER.ep0_int_en = 1;
	pUSBCtrlAddr->EIER.ep1_int_en = 1;
	pUSBCtrlAddr->EIER.ep3_int_en = 1;

	pUSBCtrlAddr->UIER.reset_int_en = 1;
	ep0State=EP0_STATE_INIT;

}

void Isr_Init(void)
{
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;

	s2440INT->rINTMOD=0x0;	  // All=IRQ mode
	s2440INT->rINTMSK=BIT_ALLMSK;	  // All interrupt is masked.

//	EdbgOutputDebugString("INFO: (unsigned)IsrUsbd : 0x%x\r\n", (unsigned)IsrUsbd);
//	EdbgOutputDebugString("INFO: (unsigned)IsrHandler : 0x%x\r\n", (unsigned)IsrHandler);

	// make value to assemble code "b IsrHandler"
	pISR =(unsigned)(0xEA000000)+(((unsigned)IsrHandler - (0x8c000000 + 0x18 + 0x8) )>>2);

	s2440INT->rSRCPND  = BIT_USBD;
	if (s2440INT->rINTPND & BIT_USBD) s2440INT->rINTPND = BIT_USBD;
	s2440INT->rINTMSK &= ~BIT_USBD;		// USB Interrupt enable.

	s2440INT->rSRCPND  = BIT_DMA2;
	if (s2440INT->rINTPND & BIT_DMA2) s2440INT->rINTPND = BIT_DMA2;
	s2440INT->rINTMSK &= ~BIT_DMA2;		// DMA Interrupt enable.
}

void IsrUsbd(unsigned int val)
{
    U8 saveIndexReg=pUSBCtrlAddr->INDEX.index;
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;

//	EdbgOutputDebugString("INFO : IsrUsbd : Interrupt occurred \r\n");

	if (s2440INT->rINTPND & BIT_DMA2)
	{
		DMA2Handler();
		goto Exit;
	}

    if(pUSBCtrlAddr->UIR.sus_int)
    {
		pUSBCtrlAddr->UIR.sus_int = 1;
		EdbgOutputDebugString("<SUS]\r\n");
    }
    if(pUSBCtrlAddr->UIR.resume_int)
    {
		pUSBCtrlAddr->UIR.resume_int = 1;
		EdbgOutputDebugString("<RSM]\r\n");
    }
    if(pUSBCtrlAddr->UIR.reset_int)
    {
		EdbgOutputDebugString("<RSET]\r\n");
    	ReconfigUsbd();
		pUSBCtrlAddr->UIR.reset_int = 1;
        PrepareEp1Fifo(); 
    }

    if(pUSBCtrlAddr->EIR.ep0_int)
    {
		EdbgOutputDebugString("EP0 Interrupt\r\n");
		pUSBCtrlAddr->EIR.ep0_int=1;
    	Ep0Handler();
    }
    if(pUSBCtrlAddr->EIR.ep1_int)
    {
		EdbgOutputDebugString("<1:TBD]\r\n");
		pUSBCtrlAddr->EIR.ep1_int=1;
    	Ep1Handler();
    }

    if(pUSBCtrlAddr->EIR.ep2_int)
    {
		pUSBCtrlAddr->EIR.ep2_int=1;
		EdbgOutputDebugString("<2:TBD]\r\n");
    }

    if(pUSBCtrlAddr->EIR.ep3_int)
    {
    	Ep3Handler();
		pUSBCtrlAddr->EIR.ep3_int=1;
    }

    if(pUSBCtrlAddr->EIR.ep4_int)
    {
		pUSBCtrlAddr->EIR.ep4_int=1;
		EdbgOutputDebugString("<4:TBD]\r\n");
    }

	if (s2440INT->rINTPND & BIT_USBD)
	{
		s2440INT->rSRCPND  = BIT_USBD;
		if (s2440INT->rINTPND & BIT_USBD) s2440INT->rINTPND = BIT_USBD;
	}

Exit:
    pUSBCtrlAddr->INDEX.index=saveIndexReg;
}

void Ep3Handler(void)
{
    int fifoCnt;
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;

    pUSBCtrlAddr->INDEX.index=3;

    if(pUSBCtrlAddr->OCSR1.out_pkt_rdy)
    {
		fifoCnt=pUSBCtrlAddr->OFCR1.out_cnt_low;

		downPt = (LPBYTE)(downPtIndex);
		RdPktEp3((U8 *)downPt,fifoCnt);
		downPtIndex += 64;
		s2440INT->rINTMSK |= BIT_USBD;		// USB Interrupt disable.
		return;
    }

    //I think that EPO_SENT_STALL will not be set to 1.
    if(pUSBCtrlAddr->OCSR1.sent_stall)
    {
	   	CLR_EP3_SENT_STALL();
   		return;
    }
}

void DMA2Handler(void)
{
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;
	volatile DMAreg *v_pDMAregs = (DMAreg *)DMA_BASE;

	s2440INT->rSRCPND  = BIT_DMA2;
	if (s2440INT->rINTPND & BIT_DMA2) s2440INT->rINTPND = BIT_DMA2;

	downPtIndex += 0x80000;

	v_pDMAregs->rDIDST2=((U32)downPtIndex+0x80000);
	v_pDMAregs->rDIDSTC2=(1<<2)|(0<<1)|(0<<0);  
	v_pDMAregs->rDCON2=v_pDMAregs->rDCON2&~(0xfffff)|(0x80000); 

	while(rEP3_DMA_TTC<0xfffff)
	{
		pUSBCtrlAddr->EP3DTL.ep3_ttl_l = 0xff;
		pUSBCtrlAddr->EP3DTM.ep3_ttl_m = 0xff;
		pUSBCtrlAddr->EP3DTH.ep3_ttl_h = 0x0f;
	}
}

void ConfigEp3DmaMode(U32 bufAddr,U32 count)
{
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;
	volatile DMAreg *v_pDMAregs = (DMAreg *)DMA_BASE;
	int i;

	pUSBCtrlAddr->INDEX.index=3;
	count=count&0xfffff; //transfer size should be <1MB
	v_pDMAregs->rDISRCC2=(1<<1)|(1<<0);
	v_pDMAregs->rDISRC2=REAL_PHYSICAL_ADDR_EP3_FIFO; //src=APB,fixed,src=EP3_FIFO
	v_pDMAregs->rDIDSTC2=(0<<2)|(0<<1)|(0<<0);
	v_pDMAregs->rDIDST2=bufAddr;       //dst=AHB,increase,dst=bufAddr
	v_pDMAregs->rDCON2=(count)|(1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(4<<24)|(1<<23)|(0<<22)|(0<<20); 
	//handshake,requestor=APB,CURR_TC int enable,unit transfer,
	//single service,src=USBD,H/W request,autoreload,byte,CURR_TC

	v_pDMAregs->rDMASKTRIG2 = (1<<1);
	//DMA 2 on

	pUSBCtrlAddr->EP3DTL.ep3_ttl_l = 0xff;
	pUSBCtrlAddr->EP3DTM.ep3_ttl_m = 0xff;
	pUSBCtrlAddr->EP3DTH.ep3_ttl_h = 0x0f;

	pUSBCtrlAddr->OCSR2.auto_clr = 1;
	pUSBCtrlAddr->OCSR2.out_dma_int_en = 1;
	//AUTO_CLR(OUT_PKT_READY is cleared automatically), interrupt_masking.
	pUSBCtrlAddr->EP3DU.ep3_unit_cnt = 1;

	*(volatile BYTE *)&pUSBCtrlAddr->EP3DC=UDMA_OUT_DMA_RUN|UDMA_DMA_MODE_EN;

	// deamnd disable,out_dma_run=run,in_dma_run=stop,DMA mode enable
    //wait until DMA_CON is effective.
	*(volatile BYTE *)&pUSBCtrlAddr->EP3DC;
	for(i=0;i<10;i++);
}

void ConfigEp3IntMode(void)
{
	volatile DMAreg *v_pDMAregs = (DMAreg *)DMA_BASE;
    pUSBCtrlAddr->INDEX.index=3;
    
    v_pDMAregs->rDMASKTRIG2= (0<<1);  // EP3=DMA ch 2
        //DMA channel off
	pUSBCtrlAddr->OCSR2.auto_clr = 0;

	//AUTOCLEAR off,interrupt_enabled (???)
	pUSBCtrlAddr->EP3DU.ep3_unit_cnt = 1;
	*(volatile BYTE *)&pUSBCtrlAddr->EP3DC=0x0;
    //wait until DMA_CON is effective.
    *(volatile BYTE *)&pUSBCtrlAddr->EP3DC;
}

#pragma optimize ("",off)
BOOL UbootReadData(DWORD cbData, LPBYTE pbData)
{
	volatile USBD_GLOBALS *usbdShMem = (USBD_GLOBALS *)(DRIVER_GLOBALS_PHYSICAL_MEMORY_START);
	volatile INTreg *s2440INT = (INTreg *)INT_BASE;
	volatile DMAreg *v_pDMAregs = (DMAreg *)DMA_BASE;
	unsigned int temp;
	int i;

Loop:
	if ( downPtIndex > readPtIndex + cbData )
	{
		memcpy(pbData, readPtIndex, cbData);
		readPtIndex += cbData;
	}
	else if (downPtIndex == DMABUFFER)
	{
		while (downPtIndex == DMABUFFER) {};	// first 64 bytes, get interrupt mode.

		if ( readPtIndex == DMABUFFER )
		{
			memcpy(pbData, readPtIndex, cbData);
			readPtIndex += cbData;
		}

		s2440INT->rSRCPND  = BIT_USBD;
		if (s2440INT->rINTPND & BIT_USBD) s2440INT->rINTPND = BIT_USBD;
		s2440INT->rINTMSK |= BIT_USBD;		// USB Interrupt disable.

		// read data with DMA operation.
		s2440INT->rSRCPND  = BIT_DMA2;
		if (s2440INT->rINTPND & BIT_DMA2) s2440INT->rINTPND = BIT_DMA2;
		s2440INT->rINTMSK &= ~BIT_DMA2;		// DMA Interrupt enable.

		pUSBCtrlAddr->INDEX.index=3;
		CLR_EP3_OUT_PKT_READY();

		ConfigEp3DmaMode(downPtIndex,0x80000);

		v_pDMAregs->rDIDST2=(downPtIndex+0x80000);	//for 1st autoreload.
		v_pDMAregs->rDIDSTC2=(1<<2)|(0<<1)|(0<<0);
		v_pDMAregs->rDCON2=v_pDMAregs->rDCON2&~(0xfffff)|(0x80000);

		while(rEP3_DMA_TTC<0xfffff)
		{
			pUSBCtrlAddr->EP3DTL.ep3_ttl_l = 0xff;
			pUSBCtrlAddr->EP3DTM.ep3_ttl_m = 0xff;
			pUSBCtrlAddr->EP3DTH.ep3_ttl_h = 0x0f;
		}
	}
	else
	{
		temp = rEP3_DMA_TTC;
		for (i = 0; i < 60000; i++ )
		{
		}
		if ( temp == rEP3_DMA_TTC )
		{
			EdbgOutputDebugString("INFO : UbootReadData : downPtIndex(0x%x) - readPtIndex(0x%x) = 0x%x\r\n", downPtIndex, readPtIndex, downPtIndex - readPtIndex);
			downPtIndex += ((unsigned int)0xfffff - (unsigned int)rEP3_DMA_TTC);
			EdbgOutputDebugString("INFO : UbootReadData : rEP3_DMA_TTC = 0x%x\r\n", rEP3_DMA_TTC);
		}

		goto Loop;
	}

	return TRUE;
}
#pragma optimize ("",on)
