www.pudn.com > S3C2410_USB_Device.rar > usbsetup.c


/************************************************************** 
 NAME: usbsetup.c 
 DESC: process the USB setup stage operations. 
 HISTORY: 
 MAR.25.2002:purnnamu: S3C2400X usbsetup.c is ported for S3C2410X. 
 AUG.20.2002:purnnamu: rEP0_CSR should be used instead of rOUT_CSR1_REG for EP0 macros. 
 **************************************************************/ 
#include "def.h" 
#include "config.h" 
#include "board.h" 
#include "2410addr.h" 
 
#include "2410usb.h" 
#include "usblib.h" 
#include "usbsetup.h" 
#include "usbout.h" 
#include "usbin.h" 
#include "usb.h" 
 
#ifdef	USB_DOWNLOAD_SUPPORT 
 
 
// *** End point information *** 
//   EP0: control 
//   EP1: bulk in end point 
//   EP2: not used 
//   EP3: bulk out end point 
//   EP4: not used 
 
// *** VERY IMPORTANT NOTE *** 
// Every descriptor size of EP0 should be 8n+m(m=1~7). 
// Otherwise, USB will not operate normally because the program 
// doesn't prepare the case that the descriptor size is 8n+0. 
// If the size of a descriptor is 8n, the 0 length packit should be sent.  
// Special thanks to E.S.Choi for reminding me of this USB specification. 
 
 
// =================================================================== 
// All following commands will operate only in case  
// - ep0_csr is valid. 
// =================================================================== 
#define CLR_EP0_OUT_PKT_RDY() 		rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)| \ 
						EP0_SERVICED_OUT_PKT_RDY )	  
#define CLR_EP0_OUTPKTRDY_DATAEND() 	rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)| \ 
						(EP0_SERVICED_OUT_PKT_RDY|EP0_DATA_END) )	  
					 
#define SET_EP0_IN_PKT_RDY() 		rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)| \ 
						(EP0_IN_PKT_READY) )	  
#define SET_EP0_INPKTRDY_DATAEND() 	rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)| \ 
						(EP0_IN_PKT_READY|EP0_DATA_END) )	  
					 
#define CLR_EP0_SETUP_END() 		rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)| \ 
						(EP0_SERVICED_SETUP_END) ) 
 
#define CLR_EP0_SENT_STALL() 		rEP0_CSR=( ep0_csr & (~EP0_WR_BITS)& \ 
						(~EP0_SENT_STALL) ) 
 
#define FLUSH_EP0_FIFO() 		{register i;while(rOUT_FIFO_CNT1_REG)i=rEP0_FIFO;} 
 
U32 ep0State; 
U32 ep0SubState; 
 
extern volatile int isUsbdSetConfiguration; 
 
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; 
 
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 Ep0Handler(void) 
{ 
    static int ep0SubState; 
//    int i; 
    U8 ep0_csr; 
 
    rINDEX_REG=0; 
    ep0_csr=rEP0_CSR; 
     
//    DbgOut("<0:%x]",ep0_csr); 
 
    //DATAEND interrupt(ep0_csr==0x0) will be ignored  
    //because ep0State==EP0_STATE_INIT when the DATAEND interrupt is issued. 
     
    if(ep0_csr & EP0_SETUP_END) 
    {    
    	 // 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. 
//   	DbgOut("[SETUPEND]"); 
		CLR_EP0_SETUP_END(); 
		if(ep0_csr & EP0_OUT_PKT_READY)  
		{ 
		    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(ep0_csr & EP0_SENT_STALL) 
    {    
//		DbgOut("[STALL]"); 
	   	CLR_EP0_SENT_STALL(); 
		if(ep0_csr & EP0_OUT_PKT_READY)  
		{ 
		    CLR_EP0_OUT_PKT_RDY(); 
		} 
	 
		ep0State=EP0_STATE_INIT; 
		return; 
    } 
 
    if((ep0_csr & EP0_OUT_PKT_READY) && (ep0State==EP0_STATE_INIT)) 
    {	 
		RdPktEp0((U8 *)&descSetup,EP0_PKT_SIZE); 
     
		switch(descSetup.bRequest) 
    	{ 
    	case GET_DESCRIPTOR: 
            switch(descSetup.bValueH)         
            { 
            case DEVICE_TYPE: 
// 	    		DbgOut("[GDD]"); 
	 	    	CLR_EP0_OUT_PKT_RDY(); 
		    	ep0State=EP0_STATE_GD_DEV_0;	         
	    		break;	 
	    		 
		    case CONFIGURATION_TYPE: 
// 			   	DbgOut("[GDC]"); 
 	    		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: 
// 		    	DbgOut("[GDS]"); 
 	    		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: 
//	    			DbgOut("[UE:STRI?]"); 
	    			break; 
	    		} 
		    	ep0SubState=0; 
		    	break; 
		    	 
	    	case INTERFACE_TYPE: 
// 	    		DbgOut("[GDI]"); 
	 	    	CLR_EP0_OUT_PKT_RDY(); 
		    	ep0State=EP0_STATE_GD_IF_ONLY_0; //for WIN98 
	    		break; 
	    		 
		    case ENDPOINT_TYPE:	    	 
// 		    	DbgOut("[GDE]"); 
 	    		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: 
//	    	    	DbgOut("[UE:GDE?]"); 
		    	    break; 
		    	} 
	    		break; 
		    default: 
//		    	DbgOut("[UE:GD?]"); 
	    		break; 
		    }	 
   		    break; 
   		     
    	case SET_ADDRESS: 
//			DbgOut("[SA:%d]",descSetup.bValueL); 
            rFUNC_ADDR_REG=descSetup.bValueL | 0x80; 
		    CLR_EP0_OUTPKTRDY_DATAEND(); //Because of no data control transfers. 
            ep0State=EP0_STATE_INIT; 
            break;    	 
             
		case SET_CONFIGURATION: 
//			DbgOut("[SC]"); 
            CLR_EP0_OUTPKTRDY_DATAEND(); //Because of no data control transfers. 
            ep0State=EP0_STATE_INIT; 
            isUsbdSetConfiguration=1;  
    	    break; 
    	     
  		default: 
//			DbgOut("[UE:SETUP=%x]",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: 
//		DbgOut("[GDD0]"); 
		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: 
//		DbgOut("[GDD1]"); 
		WrPktEp0((U8 *)&descDev+0x8,8);  
		SET_EP0_IN_PKT_RDY();             
		ep0State=EP0_STATE_GD_DEV_2; 
		break; 
 
	case EP0_STATE_GD_DEV_2: 
//		DbgOut("[GDD2]"); 
		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: 
//		DbgOut("[GDC0]"); 
		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: 
//		DbgOut("[GDC1]"); 
		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: 
//		DbgOut("[GDC2]"); 
        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: 
//		DbgOut("[GDC3]"); 
        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: 
//		DbgOut("[GDC4]"); 
		//zero length data packit  
		SET_EP0_INPKTRDY_DATAEND(); 
		ep0State=EP0_STATE_INIT;             
        break; 
 
    //=== GET_DESCRIPTOR:CONFIGURATION ONLY=== 
   	case EP0_STATE_GD_CFG_ONLY_0: 
//		DbgOut("[GDCO0]"); 
        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: 
//		DbgOut("[GDCO1]"); 
        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: 
//		DbgOut("[GDI0]"); 
        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: 
//		DbgOut("[GDI1]"); 
        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: 
//		DbgOut("[GDE00]"); 
        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: 
//		DbgOut("[GDE10]"); 
        WrPktEp0((U8 *)&descEndpt1+0,7);  
        SET_EP0_INPKTRDY_DATAEND(); 
        ep0State=EP0_STATE_INIT;             
        break; 
  
    //=== GET_DESCRIPTOR:STRING === 
   	case EP0_STATE_GD_STR_I0: 
//		DbgOut("[GDS0_0]"); 
	    WrPktEp0((U8 *)descStr0, 4 );   
	    SET_EP0_INPKTRDY_DATAEND(); 
	    ep0State=EP0_STATE_INIT;      
	    ep0SubState=0; 
	    break; 
 
	case EP0_STATE_GD_STR_I1: 
//		DbgOut("[GDS1_%d]",ep0SubState); 
		if( (ep0SubState*EP0_PKT_SIZE+EP0_PKT_SIZE)+++ 
    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;  //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  
} 
 
#endif