Quelltext /~heha/basteln/PC/fx2/fx2ata-200917.zip/fw.c

//-----------------------------------------------------------------------------
//   File:      fw.c
//   Contents:   Firmware frameworks task dispatcher and device request parser
//            source.
//
// indent 3.  NO TABS!
//
//   Copyright (c) 2001-2004 Cypress Semiconductor
//
// $Workfile: fw.c $
// $Date: 6/26/05 1:57p $
// $Revision: 10 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "atapi.h"
#include "globals.h"

//#define GD_CS_GENERAL_DESCRIPTOR 0x21
#define GD_CHANNEL_DESCRIPTOR 0x22

//#define SC_GET_CHANNEL_SETTINGS 1
//#define SC_SET_CHANNEL_SETTINGS 2

//#define SC_GET_UNIQUE_ID 0x80

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
#define DELAY_COUNT   0x9248*8L      // Delay for 8 sec at 24Mhz, 4 sec at 48
// USB constants
// Class specific setup commands
#define SC_BOMS_RESET           (0x21)      // Hard/soft depends on wValue field 0 = hard

//-----------------------------------------------------------------------------
// Code
//-----------------------------------------------------------------------------

// Task dispatcher

// Send descriptor without using autopointer.  The autopointer gets confused in several 
// situations, one of which is a host request len > 0x2000.
//
// This routine also allows the descriptors to be shared between full and high speed by
// changing the endpoint sizes of EP2 and EP6 on the fly.  
// 
static void sendDescriptorL(BYTE code*dscr,BYTE len) {
  BYTE l,j;
  AUTOPTR1H = MSB(dscr);
  AUTOPTR1L = LSB(dscr);

  if (!SETUPDAT[7] && len>SETUPDAT[6]) len=SETUPDAT[6];
// endpoint 0 FIFO size is always 64, so limit each block
  do{
    l=len; if (l>64) l=64;
    for (j=0; j<l;j++) EP0BUF[j]=XAUTODAT1;	// possibly zero bytes
    EP0BCL = l;
    len-=l;
    while (EP0CS&0x02) j=1;	// wait while EP0OUT is busy; j=1: Fake optimizer of Keil C
  }while (l==64);	// repeat when packet was full
}

static void sendDescriptor(BYTE code*dscr) {
  BYTE len=dscr[0];
  if (dscr[1] == 0x02 || dscr[1] == 0x07) len = dscr[2];	// Config or Otherspeed descriptor: Take entire length (<256)
  sendDescriptorL(dscr,len);
}

// Add a GPIO on PA3 in 56 pin package with new pinout when we're not bus powered
// Note that this routine DOES NOT exist in AT2LP
void checkGPIOonPA3()
{
    if (!bBIG_PACKAGE && !VBUS_POWERED && bNewAt2pinout)
      {
      if (mx2_config_data.GpioOE & 0x80 )
          OEA |=  1 << 3;
      else
          OEA &=  ~(1 << 3);
      PA3 = (mx2_config_data.GpioData & 0x80) >> 7;
      }
}

// Device request parser
static void onSetup(void) {
   // Making these items static doesn't hurt the stack compilation because this is an ISR.
   // It also removes them from the stack compilation, allowing them to be fit into gaps in the data space
  BYTE bmRequestType=SETUPDAT[0];
  BYTE bRequest=SETUPDAT[1];
  BYTE wValueL=SETUPDAT[2];
  BYTE wValueH=SETUPDAT[3];
  BYTE wIndexL=SETUPDAT[4];
  WORD wLength=SETUPDAT[6] | (SETUPDAT[7]<<8);
  EP0BCH = 0;                                     // Default to MSB of the length is 0

  switch (bmRequestType) {
    case 0x80:	// In, Standard, Device
    switch (bRequest) {
      case 0x00:	// *** Get Status (Device)
      EP0BUF[0] = VBUSPWRD ? 0 : 1;       // Bit 0 -- 1 = self-power, 0 = bus power
      goto okay2;	// Bit 1 -- remote wakeup enabled (0 for us)

      case 0x06:	// *** Get Descriptor
      switch(wValueH) {
	case 0x01: sendDescriptor(DeviceDscr); goto okay;	// Device
	case 0x06:            // Device Qualifier
                     // if high-speed is disabled, we are supposed to STALL this request
	if (!CT1) {sendDescriptor(DeviceQualDscr); goto okay;}	// high-speed is enabled, return the device qualifier
	break;

	case 0x02:	// Configuration
	case 0x07:	// Other Speed Configuration
	((BYTE xdata*) FullSpeedConfigDscr)[1] = wValueH;
	if (bBIG_PACKAGE) {
	  if (VBUSPWRD) {
	    ((BYTE xdata*)FullSpeedConfigDscr)[7] &= ~(1 <<6);       // Bit 6 -- 1 = self-power, 0 = bus power
	    ((BYTE xdata*)FullSpeedConfigDscr)[8] = 500/2; 
	  }else{
	    ((BYTE xdata*)FullSpeedConfigDscr)[7] |= 1 <<6;       // Bit 6 -- 1 = self-power, 0 = bus power
	    ((BYTE xdata*)FullSpeedConfigDscr)[8] = 0; 
          }
	}
	{BYTE eplenL=64, eplenH=0;
	  if ((EZUSB_HIGHSPEED() && wValueH == 0x02)	// GD_CONFIGURATION
	  || (!EZUSB_HIGHSPEED() && wValueH != 0x02)) {	// GD_OTHER_SPEED_CONFIGURATION
	    eplenL=0; eplenH=2;
	  }
	  ((BYTE xdata*)FullSpeedConfigDscr)[9+9+4] = eplenL;
	  ((BYTE xdata*)FullSpeedConfigDscr)[9+9+5] = eplenH;
	  ((BYTE xdata*)FullSpeedConfigDscr)[9+9+7+4] = eplenL;
	  ((BYTE xdata*)FullSpeedConfigDscr)[9+9+7+5] = eplenH;
	}
	sendDescriptor(FullSpeedConfigDscr); goto okay;

	case 0x03:	// String
	switch (wValueL) {
	  case 0: sendDescriptor(StringDscr0); goto okay;
	  case 1: sendDescriptor(StringDscr1); goto okay;
	  case 2: sendDescriptor(StringDscr2); goto okay;
	  case 3: sendDescriptor(StringDscr3); goto okay;
	}break;
      }break;

      case 0x08:	// *** Get Configuration
      EP0BUF[0] = Configuration;
      goto okay1;
    }break;

    case 0xA1:	// In, Class, Interface
    switch (wIndexL) {
      case 0x00:	// Interface 0 = Mass Storage
      switch (bRequest) {
	case 0xFE:	// SC_GET_MAX_LUN
        if (wLength==1) {  // Our interface number is hard coded (0) in DSCR.A51
          if (b2LUN_SET_BY_EEPROM) EP0BUF[0] = 1;
          else if (b1LUN_SET_BY_EEPROM) EP0BUF[0] = 0;
          else EP0BUF[0] = deviceCount-1;
          goto okay1;
        }break;
      }break;
#if CSM_SUPPORT
      case 0x01:
      switch (bRequest) {
	case 0x01:	// SC_GET_CHANNEL_SETTINGS
	EP0BUF[0] = 1;
	goto okay1;

	case 0x06:	// Get Descriptor
	switch (wValueH) {
	  case 0x22: sendDescriptor(CSMIntrfcDscr); goto okay;	//GD_CHANNEL_DESCRIPTOR
	  case 0x23: sendDescriptor(CSMIntrfcDscr); goto okay;	//GD_CSM_DESCRIPTOR
	  case 0x24: sendDescriptor(CSMIntrfcDscr); goto okay;	//GD_CSMV_DESCRIPTOR
        }break;

	case 0x21:	// GD_CS_GENERAL_DESCRIPTOR
	sendDescriptor(CSMGeneralDscr);
	goto okay;

	case 0x80:	// SC_GET_UNIQUE_ID
	sendDescriptorL(CSMSerial,IDE_ID_SERIAL_LEN);
	goto okay;
      }break;
#endif
#if HID_SUPPORT
      case 0x02:
      switch (bRequest) {
        case 0x06:	// Get Descriptor
	switch (wValueH) {
	  case 0x21: sendDescriptor(HIDDscr); goto okay;	// Get-Descriptor: HID
	  case 0x22: sendDescriptorL(HIDReportDscr,HIDReportDscrLen); goto okay;	// Get-Descriptor: Report
	}break;
      }break
#endif
    }break;

    case 0x81:	// In, Standard, Interface
    switch (bRequest) {
      case 0x00:	// *** Get Status (Interface)
      EP0BUF[0] = 0;
      goto okay2;

      case 0x0A:	// *** Get Interface
      EP0BUF[0] = AlternateSetting;
      goto okay1;
    }break;

    case 0x01:	// Out, Standard, Interface
    switch (bRequest) {
      case 0x0B:	// *** Set Interface
            // From USB 2.0 spec 9.4.5
            // The Halt feature is reset to zero after either a SetConfiguration() or SetInterface() request even if the
            // requested configuration or interface is the same as the current configuration or interface.
      EP2CS = 0;           // Clear stall bit
      EP6CS = 0;
      EP1INCS = 0;
            // Clear Data Toggles.
      TOGCTL = 0x2;     // Reset data toggle for EP2
      TOGCTL = 0x22;
      TOGCTL = 0x16;    // Reset data toggle for EP6
      TOGCTL = 0x36;
      TOGCTL = 0x11;    // Reset data toggle for EP1
      TOGCTL = 0x31;
      AlternateSetting = wValueL;
      goto okay;
    }break;

    case 0x00:	// Out, Standard, Device
    switch (bRequest) {
      case 0x03:	// *** Set Feature
      switch (wValueL) {
        case 0x02: goto okay;
		// Set Feature Test Mode.  The core handles this request.  However, it is
		// necessary for the firmware to complete the handshake phase of the
		// control transfer before the chip will enter test mode.  It is also
		// necessary for FX2 to be physically disconnected (D+ and D-)
		// from the host before it will enter test mode.
      }break;

      case 0x09:	// *** Set Configuration
            // From USB 2.0 spec 9.4.5
            // The Halt feature is reset to zero after either a SetConfiguration() or SetInterface() request even if the
            // requested configuration or interface is the same as the current configuration or interface.
      EP2CS = 0;           // Clear stall bit
      EP6CS = 0;
      EP1INCS = 0;
      Configuration = wValueL;
            // compliance code
      if (!Configuration && VBUS_POWERED) powerOff();
      goto okay;
    }break;

    case 0x82:	// In, Standard, Endpoint
    switch (bRequest) {
      case 0x00:	// *** Get Status (Endpoint)
      switch (wIndexL) {
        case 0x02: EP0BUF[0] = EP2CS & 0x01; goto okay2;
	case 0x86: EP0BUF[0] = EP6CS & 0x01; goto okay2;
	case 0x81: EP0BUF[0] = EP1INCS & 0x01; goto okay2;
	case 0x00: EP0BUF[0] = 0; goto okay2;
      }break;
    }break;

    case 0x02:	// Out, Standard, Endpoint
    switch (bRequest) {
      case 0x01:	// *** Clear Feature (Endpoint)
      switch (wValueL) {
	case 0x00:	// ** STALL
	switch (wIndexL) {
                        // do not clear endpoint STALLs if we received an invalid CBW.
                        // The BOT MSC Spec says we must stay STALL'd until we get reset
	  case 0x2:
	  ResetAndArmEp2();
	  TOGCTL = 0x2;
	  TOGCTL = 0x22;       // reset data toggle
	  EP2CS = 0;           // Clear stall bit
	  goto okay;

	  case 0x86:
	  TOGCTL = 0x16;
	  TOGCTL = 0x36;       // reset data toggle
	  EP6CS = 0;           // Clear stall bit
	  goto okay;

	  case 0x81:
	  TOGCTL = 0x11;
	  TOGCTL = 0x31;         // reset data toggle
	  EP1INCS = 0;           // Clear stall bit
	  goto okay;
        }break;
      }break;

      case 0x03:	// *** Set Feature (Endpoint)
      switch (wValueL) {
	case 0x00:	// ** STALL
	switch (wIndexL) {
	  case 0x02: EP2CS = 0x01; goto okay;	// Set stall bit
	  case 0x86: EP6CS = 0x01; goto okay;
	  case 0x81: EP1INCS = 0x01; goto okay;
        }break;
      }break;
    }break;

    case 0x21:		// Out, Class, Interface
    switch (wIndexL) {
      case 0x00:	// Interface 0 = Mass Storage
      switch (bRequest) {
	case 0xFF:	// SC_MASS_STORAGE_RESET (wValueL==0)
		// Verify that the command is actually a MS reset command sent to the proper interface
	if (!wLength) { // Our interface number is hard coded (0) in DSCR.A51
		// All we really need to do in response to a MSC Reset is restart using
		// a soft reset (jump to 0x00).
		// This will re-initialize the drive and endpoints.
	  EZUSB_IRQ_CLEAR();
	  INT2CLR = 0x01;	// Clear SUDAV IRQ
	  phaseErrorState = 0;
		// force a soft reset after the iret.
          EA = 0;
          softReset();
	  goto okay;
        }break;
      }break;
#if CSM_SUPPORT
      case 0x01:	// Interface 1 = CSM
      switch(bRequest) {
	case 0x02:	// SC_SET_CHANNEL_SETTINGS
	goto okay;
      }break;
#endif
#if HID_SUPPORT
      case 0x02:
      switch(bRequest) {
	case 0x09:	// HID_SET_REPORT
	EP0BCH = 0;
	EP0BCL = 0; // Clear bytecount to allow new data in; also stops NAKing
	while(EP0CS & bmEPBUSY); // wait for the report
	report[0] = EP0BUF[0];
	report[1] = EP0BUF[1];
	receivedReport_Flag = TRUE;
	goto okay;

	case 0x0A:	// HID_SET_IDLE
	goto okay;
      }break;
#endif
    }break;

    case 040:		// Out, Vendor, Device
    switch (bRequest) {
      case 0x01:	// Load (write) config data
      if (!wValueL || wValueL==2) {     // 0 = Write config bytes, 2 = Write EEPROM AND config bytes
	EP0BCH = 0;
	EP0BCL = 0; // Clear bytecount to allow new data in; also stops NAKing
	while (EP0CS & 0x01);
	if (wIndexL < sizeof(MX2_CONFIG_DATA))
	 mymemmovexx((BYTE xdata*)&mx2_config_data + wIndexL, EP0BUF, min(sizeof(MX2_CONFIG_DATA)-wIndexL, wLength));
	if (wIndexL + wLength >= sizeof(MX2_CONFIG_DATA))
	 mymemmovexx(halfKBuffer, EP0BUF, EP0BCL-max(0,sizeof(MX2_CONFIG_DATA)-wIndexL));
	if (wValueL==2) {     // Write EEPROM too
	  BYTE i;
	  for (i=0; i< EP0BCL; i+= EEPROM_PAGE_SIZE) 
	   EEPROMWriteBlock(wIndexL+i+CONFIG_SPACE_START, EP0BUF+i, min(EEPROM_PAGE_SIZE, EP0BCL-i));
	}
	wLength -= EP0BCL;
	wIndexL += EP0BCL;
	EP0BCL = 0;
	while (wLength) {
	  while (EP0CS & 0x01);
	  mymemmovexx(halfKBuffer + wIndexL - sizeof(MX2_CONFIG_DATA), EP0BUF, EP0BCL);
	  if (wValueL==2) {	// Write EEPROM too
	    BYTE i;
	    for (i=0; i< EP0BCL; i+=EEPROM_PAGE_SIZE)
	     EEPROMWriteBlock(wIndexL+i+CONFIG_SPACE_START, EP0BUF+i, EEPROM_PAGE_SIZE);
	  }
	  wLength -= EP0BCL;
	  wIndexL += EP0BCL;
	  EP0BCL = 0;
	}
	IOEShadow = (mx2_config_data.GpioData << 2) | (IOEShadow & 3);    
	IOE = IOEShadow;
	OEE = mx2_config_data.GpioOE << 2 | (OEE & 3);
	checkGPIOonPA3();
	goto okay;
      }break;
    }break;

    case 0xC0:		// In, Vendor, Device
    switch (bRequest) {
      case 0x02:	// Read config data
      if (wValueL==2) {	// Read EEPROM 
	while (wLength) {
	  BYTE l=64; if (wLength<64) l=wLength;
	  while (EP0CS & 0x01);
	  EEPROMRead(wIndexL+CONFIG_SPACE_START, l, (BYTE xdata *) EP0BUF);
	  EP0BCL = l;
	  wLength -= l;
	  wIndexL += l;
	}
	goto okay;
      }else{
	BYTE l=64; if (wLength<64) l=wLength;
	if (wIndexL < sizeof(MX2_CONFIG_DATA))
	 mymemmovexx(EP0BUF, (BYTE xdata *) &mx2_config_data + wIndexL, min(sizeof(MX2_CONFIG_DATA)-wIndexL, wLength));
	if (wIndexL >= sizeof(MX2_CONFIG_DATA))
	 mymemmovexx(EP0BUF, halfKBuffer + wIndexL, l);
	else // transfer is split between the two sections
	 mymemmovexx(EP0BUF + max(sizeof(MX2_CONFIG_DATA)-wIndexL, 0), 
		halfKBuffer, 
		64-max(0,sizeof(MX2_CONFIG_DATA)-wIndexL));
	EP0BCL = l;
	wLength -= l;
	wIndexL += l;
        while (wLength) {
	  while (EP0CS&0x01);
	  l=64; if (wLength<64) l=wLength;
	  mymemmovexx(EP0BUF, halfKBuffer + wIndexL - sizeof(MX2_CONFIG_DATA),l);
	  EP0BCL = l;
	  wLength -= l;
	  wIndexL += l;
	}
      }goto okay;
    }break;
  }// switch (bmRequestType)
  EP0CS = 0x01;		// stall EP0;
  return;
okay2:
  EP0BUF[1] = 0;
  EP0BCL = 2;
  goto okay;
okay1:
  EP0BCL = 1;
okay:
  EP0CS = 0x80;		// Acknowledge handshake phase of device request
}

// Wake-up interrupt handler
void resume_isr(void) interrupt WKUP_VECT
{
   EZUSB_CLEAR_RSMIRQ();
}


static void onUres(void) {
   // whenever we get a USB reset, we should revert to full speed mode
  wPacketSize = FS_BULK_PACKET_SIZE;
  EP6FIFOPFH = 0x80;
  EP6FIFOPFL = 0x60;
  EP6AUTOINLENH = MSB(wPacketSize);
  EP6AUTOINLENL = LSB(wPacketSize);
  abortGPIF();
  FIFORESET = 6;
  ResetAndArmEp2();
   // clear the stall and busy bits that may be set
  EP2CS = 0;     // set EP2OUT to empty and clear stall
  EP6CS = 0;     // set EP6OUT to empty and clear stall
   // Initialize USB variables to make chapter 9 happy
  AlternateSetting = Configuration = 0;
   
  if (currentState != UNCONFIGURED) {
    EA = 0;
      // force a soft reset after the iret.
    softReset();
  }
}

static void onHighspeed(void) {
  if (USBCS&0x80) {	// HiSpeed?
    WORD CT4Count = 272;
      
      // Look for CT4.3 (JK activity) inactive for 500us
      // This loop was hand-counted to be 22/12 = 1.8us long, so 272 iterations are 500us
      // With the CT2 check, this loop is 31/12 =   193 iterations are 500us
    while(CT2 != 0xd && --CT4Count) {
      if (CT4 & 8) CT4Count = 193;
    }
    if (CT2 == 0xc) {	// If we timed out in state C, bump the state machine to state D
      CT1 = 2;
      SYNCDELAY;
      CT2 = 0xd;
      SYNCDELAY;
      CT1 = 0;
    }
    wPacketSize = HS_BULK_PACKET_SIZE;
    EP6FIFOPFH = 0x99;         // Allow the FIFO to hold 3 full packets + 0x190 bytes.
    EP6FIFOPFL = 0x90;
  }
  EP6AUTOINLENH = MSB(wPacketSize);
  EP6AUTOINLENL = LSB(wPacketSize);
}

void main(void) {
  BYTE usbirq;
  MPAGE=0xE6;	// let compiler access xdata registers at 0xE6xx via R0 or R1
  USBCS=0x02;	// set the renum bit so that firmware handles SETUP transfers.

   // if we are hung up in a GPIF transfer, abort it.  How could this happen?  If
   // we ended up here after a USB Reset or a MSC Reset, it is possible that the
   // GPIF is hung waiting for a transfer that will never complete.
   abortGPIF(); // TPM: Unconditionally abort

   EZUSB_ENABLE_RSMIRQ();	// Wake-up interrupt

   TD_Init();      

   Sleep = 0;
   driveIsInStandby = 0;

   noFlashMedia = 1;
   ejected = 0;
   udmaErrorCount = 0;
   oldButtons = 0xff;

   // complete the handshake phase of any pending SETUP transfer.
   // The only time this should happen is after a MSC Reset.  We want
   // to go through all of the EP init code before handshaking the status
   // phase of the MSC Reset.
   if (IN_MASS_STORAGE_CLASS_RESET) EP0CS = 0x80;
   EA = 1;	// Enable 8051 interrupts
   TR0 = 1;	// Make sure that the timer ISR runs at once.  This will take care of the ATA_ENABLE line

   // Reconnect to USB if we have our MAX_LUN or if we need a SET_CONFIGURATION msg
  if (VBUS_POWERED || b1LUN_SET_BY_EEPROM || b2LUN_SET_BY_EEPROM) {
    USBCS = 0x02;	// Reconnect to USB.  This line has no effect in a system that's already connected.
  }

   // Enable interrupts and wait here until we receive a SET_CONFIGURATION message.
   // why?
   // because we can not identify bus-powered drives until we can turn on nPWR500.
   // We no longer pull the serial number from the drive.  We will not get a GET_MAX_LUN
   // command until after the drives are turned on.

   // Okay to connect here IF we're not planning to update the number of LUNs
  if (!(bFirstTime || deviceCount == 0x80))  USBCS = 0x02;

  if (!mfgMode) ATAInit();
   // Reconnect to USB.  This line has no effect in a system that's already connected.
  USBCS = 0x02;

  CKCON = CKCON&0xF8;	// Set stretch to 0 (after renumeration)

   // Check for spurious sleep flag.  We will often detect SUSPEND during startup but it's probably over now.
  if (Sleep) {
    USBCS = 0x06;
    USBIRQ = 0x02;
    EZUSB_Delay(3);
    if (USBIRQ & 0x02) Sleep = 0;
  }         

//   FIFORESET = 0;    // turn off nakall
   // Task Dispatcher
  for(;;) {	// Main Loop
      ////////////////////////////////////////////////////////////////////
      // There are four sleep states in a removable-drive system, three
      // in a non-removable system.
      //
      // 1. Unplugged -- Reached whenever ATA_EN/VBUS is low.  D+ is not pulled up.
      //       This state is coded in checkATAEnable(), reached via the ISR or from this routine.
      //       This state wakes only on WAKEUP# 0-->1, so WAKEUPCS = bmWU | bmWUPOL | bmWUEN
      //       The code passes through softReset at the end of this state.
      // 2. Active -- D+ is pulled up.  This is the main code path.
      // 3. Sleeping -- CPU is shut down waiting for D+ to go active.  In the removable drive (CF) case,
      //       WU2 can also wake the device so that card swaps during suspend can be detected.
      // 4. Card swap -- If we are awakened by WU2, set the noFlashMedia flag so we will report new media 
      //       the next time that we detect a CF.  This detection takes place in TD_Poll()
      ////////////////////////////////////////////////////////////////////
#if STANDBY_IMMEDIATE
    WAKEUPCS = 0x45;
    if (Sleep || (WAKEUPCS & 0x40) || (!bNewAt2pinout && !VBUS_PRESENT)) {     // check VBUS and old part's VBUS detector
      WORD i;
      Sleep = FALSE;

         //////////////////////////////////////////////////
         // Special purpose power-saving code.
         //
         // Expected conditions:  
         //     Self-powered, no bus-sharing, single IDE device
         //
         // This code will wait 100ms before turning off the drive.
         // This is to debounce any short sleep conditions that occur, like the 
         // ~75ms sleep period that many hosts do during startup.
         //////////////////////////////////////////////////
      USBCS = 0x06;	// NOSYNOF and RENUM
      USBIRQ = bmSOF;
      for (i = 0; i < 500; i++) {
        EZUSB_Delay(1);
        if (USBIRQ & bmSOF) break;
      }

      if (!(USBIRQ & bmSOF)) standbyImmediate();
#else
      if (Sleep)
      {
         Sleep = FALSE;

      if (!bScsi) flushCache();
#endif

         // Before going to sleep, check the tri-state pin one last time.
         // This will also catch the case where we were woken up by the tri-state pin and must go back to sleep.
      EZUSB_Delay(10);      // Make sure VBUS has time to go away before checking it.
      checkATAEnable();
      OEC = PORTC_OE_SUSPEND;
      OEE = PORTE_OE_SUSPEND | (mx2_config_data.GpioOE << 2);

      powerOff();

         // Drive the data bus low.  This code is only called in suspend, not in the other power-off cases.
      if (VBUS_POWERED) {
        IFCONFIG &= ~3;   // Turn off GPIF control of ports B and D.
        IOB = IOD = IOA = 0;
        OEB = OED = 0xff;
        OEA = 0xf7;
        GPIFCTLCFG = 0x80;   // 
        GPIFIDLECTL = 0x70;  // x111x000 - CTL3 not enabled.  Drive the CTL lines LOW
      }
         
#if STANDBY_IMMEDIATE
         // Standby_Immediate case kills all of the stuff done in check_ata_enable so that 
         // it can turn off the drive in this background loop.  This means that WAKEUP# could
         // be high or low here in the STANDBY_IMMEDIATE case
      WAKEUPCS = 0xC5;
      if (WAKEUPCS & 0x40) WAKEUPCS = WAKEUPCS = 0xD5;
#else
         // Wake up on D+ traffic, WAKEUP 1-->0.
         // If there is a CF, wake up on CF insertion too.
      if (bDRVPWRVLD_ENABLE) {
        if (CF_DETECT_) WAKEUPCS = 0xC7;	// No CF, wake on low
        else WAKEUPCS = 0xE7;	// CF there, wake on high
      }else WAKEUPCS = 0xC5;
#endif

      EZUSB_Susp();         // Place processor in idle mode.

         // If we were woken up by a CF insertion, go back to sleep after one loop.
      if (WAKEUPCS & bmWU2) Sleep = TRUE;

         // Undo "drive data bus low" code above.
      if (VBUS_POWERED) {
        OEA = PORTA_OE;
        OUTATAPI = (BYTE)(ATAPI_IDLE_VALUE);
        IFCONFIG = IFCONFIG_DEFAULT;    
        GPIFCTLCFG = 0x80;   // 
        GPIFIDLECTL = 0x77;  // x111x000 - CTL3 not enabled.  Drive the CTL lines LOW
      }

      OEC = PORTC_OE;
      OEE = PORTE_OE | (mx2_config_data.GpioOE << 2);

      powerOn();
    }  // endif (sleep)
// Poll for USB activity
    usbirq=USBIRQ=USBIRQ;	// clear and save all requests
    if (usbirq&0x08) {	// 3 ms USB inactivity seen
      Sleep = TRUE;
    }
    if (usbirq&0x20) {	// Switch to high-speed done?
      onHighspeed();
    }
    if (usbirq&0x10) {	// USB RESET seen
      onUres();
    }
    if (usbirq&0x01) {	// SUDAV = EP0 Setup Data Available
      onSetup();
    }
    TD_Poll();     
  }	// End while-forever loop
}
Vorgefundene Kodierung: ASCII (7 bit)2