⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 periph.c

📁 cy68013a USB2.0 highspeed mass storage source code
💻 C
📖 第 1 页 / 共 3 页
字号:

      if (CbwLun == currentLunNum && !(mymemcmpa(prevCmd,&EP2FIFOBUF[0x0F],12+1)))
         {
         BYTE driveStatus;
   
         // Save the tag for use in the response
         cbwTagLow = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG));
         cbwTagHi =  *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG+2));
   
         if (!bScsiRegsPreloaded)
            preloadSCSIRegs();
   
         EP2BCL = 0x80;         // Release the endpoint buffer
   
         // Send the "ATAPI packet" command
         writePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_ATAPI_PACKET);
   
         // Wait for the register block to be non-busy and to request data
         // CANNOT call waitForDRQBit because that routine waits for the IRQ pin to be set
         while (     (   (driveStatus = readATAPI_ALT_STATUS_REG()) 
                       & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_DRQ_BIT)  )
                  != ATAPI_STATUS_DRQ_BIT)
                  ;
         if(driveStatus & ATAPI_STATUS_ERROR_BIT)
            {
            sendUSBS(USBS_FAILED);
            currentState = WAIT_FOR_CBW;
            }
         // Send our stored command
         while (!gpifIdle())
           {
           }
         GPIFWFSELECT = 0;    // PIO write is waveform 0
         
         // Write the address/chip selects
         OUTATAPI = ATAPI_DATA_REG | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
   
         sendprev();
         while (!gpifIdle())
           {
           }
   
         if (directionIn)
            sendUSBS(scsiReadUdma());
         else
            sendUSBS(scsiWriteUdma());    // Send USBS and scsiWriteUdma will set us up for the next time....
         return;
         }
      }
   processCBWHeader();

   if (!(CbwLun == currentLunNum))
   {
      // Before we change waveforms, tell the ATA interface that we're going to talk to the master.
      // This allows us to use some of the ATA signals for the CF while the slave device ignores them.
      // This works well as long as we don't write to a register that affects both devices, like
      // the device select register, or the SRST bit in the control register.
      mymemmove((BYTE *)&ActiveLunConfigData,(BYTE *)&DeviceConfigData[CbwLun], sizeof(DEVICE_CONFIG_DATA));
      ActiveLunBits = LunBits[CbwLun];
      sensePtr = sensePtrs[CbwLun];
      currentLunNum = CbwLun;

      {
         EP2FIFOCFG = EP6FIFOCFG = bmZEROLENIN | bmWORDWIDE;      // ATA/ATAPI is word-wide

         // We've switched devices.  Do we need to switch PIO modes too?
         // if (!(DeviceConfigData[0].MaxPIO == DeviceConfigData[1].MaxPIO))
         // ALWAYS switch.  It's easier than special casing startup.
         {
            // switch to PIO4
            if(ActiveLunConfigData.MaxPIO & PIO4) 
            {
               mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA+4, 8 + 4);
               mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32+4, 8 + 4);
            }
            // switch to PIO3
            else if(ActiveLunConfigData.MaxPIO & PIO3) 
            {
               mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA+4, 8 + 4);
               mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32+4, 8 + 4);
               ((BYTE xdata *)&GPIF_WAVE_DATA)[0] = 0x6;
               ((BYTE xdata *)&GPIF_WAVE_DATA)[32] = 0x6;
            }
            // switch to PIO0
            else 
            {
               mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA, 8 + 4);
               mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32, 8 + 4);
            }
            
            // Now switch UDMA / DMA modes
            if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_UDMA0)
            {
               mymemmovexx(&(GPIF_WAVE_DATA) + 64, (BYTE xdata *) WaveDataPioUDMA+64, 64);
            }
            else if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_DMA0)
            {
               mymemmovexx(&(GPIF_WAVE_DATA) + 64, (BYTE xdata *) WaveDataPioUDMA+128, 64);
            }
         }
      }
   }

   driveIsInStandby = 0;
   // Config CB
   // Our personal "firmware update" command
   if (EP2FIFOBUF[0xf] == 0xfb && !(EP2FIFOBUF[CBW_FLAGS] & CBW_FLAGS_DIR_BIT))
      {
      BYTE saveAddr = eepromAddr;
      // relinquish control of the bulk buffer occupied by the CBW
      EP2BCL = 0x80;     

      eepromAddr = 0x51;
      // Write the entire EEPROM
      EEPROMWrite(dataTransferLenLSW, 0x00);
      eepromAddr = saveAddr;
      sendUSBS(USBS_PASSED);
      }
   // CONFIG CB
   else if (EP2FIFOBUF[0xf] == mx2_config_data.AtaCommand)
      {
      sendUSBS(processConfigCBCommand());
      }
   else if (directionIn || (!dataTransferLenLSW && !dataTransferLenMSW))
      {
      currentState = RECEIVED_IN_CMD;
      if (bScsi)
         {
         sendUSBS(generalSCSIInCommand());
         if (deviceCount == 1)
            {
            preloadSCSIRegs();
            bScsiRegsPreloaded = 1;
            }
         }
      #if DEVICE_TYPE_IS_IDE
      else
         sendUSBS(generalIDEInCommand());
      #endif
      while (!gpifIdle());             // wait till GPIF is done before getting real data
      OUTATAPI = ATAPI_IDLE_VALUE;           // Clear ATA control lines.  Really only needed to turn off the CF LED.
      sensePtrs[currentLunNum] = sensePtr;
      }
   else
       {
       currentState = RECEIVED_OUT_CMD;
       if (bScsi)
         {
         sendUSBS(generalSCSIOutCommand());
         if (deviceCount == 1)
            {
            preloadSCSIRegs();
            bScsiRegsPreloaded = 1;
            }
         }
      #if DEVICE_TYPE_IS_IDE
      else
           sendUSBS(generalIDEOutCommand());
      #endif
      while (!gpifIdle());             // wait till GPIF is done before getting real data
      OUTATAPI = ATAPI_IDLE_VALUE;           // Clear ATA control lines.  Really only needed to turn off the CF LED.
      sensePtrs[currentLunNum] = sensePtr;
       }

   currentState = WAIT_FOR_CBW;
}   



void sendUSBS(BYTE passOrFail)
{
   bit done = 0;
   
   // generalIDEx/generalSCSIx command returns here with passOrFail status bit
   // which is re-cast as the error byte of CSW

   while (!done)
   {
      if( (!(EP6CS & bmEPFULL)) && (!(EP6CS  & bmEPSTALL)))      // Wait for an available buffer
      {
         // Eliminate any data in the OUT endpoint or FIFO
         // This can happen in the Ho > Dn and Ho > Do cases.
         if(!(EP2468STAT & bmEP2EMPTY) || EP2FIFOBCL || EP2FIFOBCH)   
            ResetAndArmEp2();

         // Fill the buffer & send the data back to the host
         AUTOPTRL2 = LSB(EP6FIFOBUF);

         XAUTODAT2 = 'U';        // Believe it or not, this is pretty efficient!
         XAUTODAT2 = 'S';
         XAUTODAT2 = 'B';
         XAUTODAT2 = 'S';

         XAUTODAT2 = MSB(cbwTagLow);
         XAUTODAT2 = LSB(cbwTagLow);
         XAUTODAT2 = MSB(cbwTagHi);
         XAUTODAT2 = LSB(cbwTagHi);

         // have to store LSB first
         XAUTODAT2 = ((BYTE *)&dataTransferLen)[3];    // "Residue"
         XAUTODAT2 = ((BYTE *)&dataTransferLen)[2];    // "Residue"
         XAUTODAT2 = ((BYTE *)&dataTransferLen)[1];    // "Residue"
         XAUTODAT2 = ((BYTE *)&dataTransferLen)[0];    // "Residue"
         
         XAUTODAT2 = passOrFail;                 // Status
         EP6BCH = 0;
         EP6BCL = 13;
         done = 1;

         // If we're in phase error, STALL the OUT endpoint to make sure the host resets us (and the drive)
         if (passOrFail == USBS_PHASE_ERROR)
            {
            EP2CS = bmEPSTALL;
            while( !(EP6CS & bmEPEMPTY))  // Wait for an available buffer
               ;
            EP6CS = bmEPSTALL;
            phaseErrorState = 1;
            }
      }
   }

   // Stall the IN endpoint if we're in phase error state.
   if (phaseErrorState)
      {
      while( !(EP6CS & bmEPEMPTY) )
         ;
      EP6CS = bmEPSTALL;
      }
   #if DEVICE_TYPE_IS_IDE
   if (attemptFastRead)
      fastReadStart();
   else if (attemptFastWrite)
      fastWriteStart();
   else
   #endif 
      if (attemptFastScsi)
      fastSCSIStart();
}   

void failedIn()
{
   // Stall if the host is still expecting data.  Make sure
   // endpoint is empty before doing the stall.
   if (dataTransferLen)
      {
      if (!bShortPacketSent && SHORT_PACKET_BEFORE_STALL)
         {
         while( !(EP6CS & bmEPEMPTY) )
            ;
         EP6BCH = 0;    // Terminate with NULL packet, then STALL.  This 
         EP6BCL = 0;    // addresses an issue with the current EHCI driver (1/02)
         }

      while( !(EP6CS & bmEPEMPTY) )
         ;

      EP6CS = bmEPSTALL; // TPM
      }
}

bit waitForBusyBit()
{
    BYTE driveStatus;

    do
    {
        driveStatus = readATAPI_ALT_STATUS_REG();
    }
    while((driveStatus & (ATAPI_STATUS_BUSY_BIT)));    // Do-while
    
    // Some drives clear the busy bit asynchronously.  Read the reg one more time to be sure.
    driveStatus = readATAPI_ALT_STATUS_REG();

    if ((driveStatus & ATAPI_STATUS_ERROR_BIT))
        return(USBS_FAILED);
    else
        return(USBS_PASSED);
}   

#pragma DISABLE
void mymemmovexx(BYTE xdata * dest, BYTE xdata * src, WORD len)
{
   AUTOPTR1H = MSB(dest);
   AUTOPTR1L = LSB(dest);

    while (len--)
    {
        XAUTODAT1 = *src++;
    }
}    

// Used in ISRs to avoid conflicts with mymemmovexx()
void mymemmovexxISR(BYTE xdata * dest, BYTE xdata * src, WORD len)
{
    while (len--)
    {
        *dest++ = *src++;
    }
}
    
void mymemmove(BYTE data * dest, BYTE data * src, BYTE len)
{
    while (len--)
    {
        *dest++ = *src++;
    }
}    


// mdnspd
//BYTE mymemcmp(BYTE idata * s1, BYTE xdata * s2, WORD len)
//{
//   while (len--)
//   {
//      if (!(*s1++ == *s2++))
//      {
//         return(1);
//      }
//   }
//
//   return(0);
//}

// mdnspd
void mymemmoveix(BYTE idata * dest, BYTE xdata * src, BYTE len)
{
    while (len--)
    {
        *dest++ = *src++;
    }
}


//-----------------------------------------------------------------------------
// USB Interrupt Handlers
//   The following functions are called by the USB interrupt jump table.
//-----------------------------------------------------------------------------


// Setup Data Available Interrupt Handler
void ISR_Sudav(void) interrupt 0
{
   EZUSB_IRQ_CLEAR();
   INT2CLR = bmSUDAV;         // Clear SUDAV IRQ

   SetupCommand();
}


void ISR_Ures(void) interrupt 0
{
   // 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;

   EZUSB_IRQ_CLEAR();   
   INT2CLR = bmURES;        // Clear URES IRQ
   
   if (currentState != UNCONFIGURED)
   {
      EA = 0;
      // force a soft reset after the iret.
      softReset();
   }
}

void ISR_Susp(void) interrupt 0
{
   Sleep = TRUE;
   EZUSB_IRQ_CLEAR();
   INT2CLR = bmSUSP;
}

void ISR_Highspeed(void) interrupt 0
{
   if (EZUSB_HIGHSPEED())
   {
      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;
         WRITEDELAY();
         CT2 = 0xd;
         WRITEDELAY();
         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);


   EZUSB_IRQ_CLEAR();
   INT2CLR = bmHSGRANT;
}


#define FW_STRETCH_VALUE_5 5

void ResetAndArmEp2()
{
   // adjust stretch to allow for synchronization delay.  We are about
   // to do several back to back writes to registers that require a
   // synchroniztion delay.  Increasing stretch allows us to meet
   // the delay requirement.  See "Synchroniztion Delay" in the Technical

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -