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

📄 scsi.c

📁 cy68013a USB2.0 highspeed mass storage source code
💻 C
📖 第 1 页 / 共 3 页
字号:
                  bDone = 1;                    
                  break;
                  }
               // Check if drive is finished with transaction.
               else if(!(driveStatus & ATAPI_STATUS_DRQ_BIT))
                  {
                  bDone=1;
                  cReturnStatus = USBS_PASSED;
                  }
               else if ((readPIO8(ATA_SECTOR_COUNT_REG) & 2))  // On the first DRQ, check to see if the drive is trying to do IN our OUT (Ho <> Di)
                  {
                  bDone=1;      // No more data
                  cReturnStatus = USBS_PHASE_ERROR;
                  break;
                  }
               else
                  {
                  wDriveDataLen = getDriveDataLen();
                  } // end else
               } // end if !wDriveDataLen

            if (wDriveDataLen > dataTransferLen)      // Host has less data than the drive wants.  Phase error!
               {
               bDone=1;      // No more data
               cReturnStatus = USBS_PHASE_ERROR;
               break;
               }

            // wAmountToWrite is limited by two factors:
            // -- wDriveDataLen -- The amount of data remaining in the drive's most recent request
            // -- wPacketSize-wAmountSent -- The amount of data remaining in our buffer
            wAmountToWrite = min(wPacketSize-wAmountSent, wDriveDataLen);
            wAmountToWrite = min(dataTransferLen, wAmountToWrite);
   
            // Send the packet and adjust counts.  
            if (wAmountToWrite)
               writePIO16(wAmountToWrite+1);
            dataTransferLen -= wAmountToWrite;
            wDriveDataLen -= wAmountToWrite;
            wAmountSent += wAmountToWrite;
            } // end while(within current packet)
         } // end if(data in endpoint buffer)
      } // end while(all data)

   // If the device still wants more data from the host at this point, it's a phase error (case 13)
   driveStatus = waitForDRQBit(0);
   if ((driveStatus & ATAPI_STATUS_DRQ_BIT) || wDriveDataLen)
      cReturnStatus = (USBS_PHASE_ERROR);   
   else if (driveStatus & ATAPI_STATUS_ERROR_BIT)
      cReturnStatus = (USBS_FAILED);   
      
   // If there is still data in our buffer there are several possibilities:
   // 1)  Data in our buffer.  No more data coming from the host.  Reset the endpoint.
   // 2)  Buffer full, more data expected from the host.  STALL.
   // 3)  Data still on the way from the host that will go beyond our buffer size.  STALL.
   // 4)  Data still on the way from the host that will fit within our buffer size.  Wait for the data, then reset the endpoint.
   //       There is no clean way to wait for the data that works with the current TCL scripts.  Just reset the endpoing.
   //
   if (dataTransferLen && !bShortPacketReceived)
      stallEP2OUT();
   // This is done in send_usbs()
   //   else if (!(EP2468STAT & bmEP2EMPTY))         // Discard residue in the buffer if needed.  This is required so that the FIFO will give the buffer back to us (if we DON'T stall)
   //                           // For example, case 11 with 250 bytes of data.
   //      ResetAndArmEp2();     
   return(cReturnStatus);
}


//-----------------------------------------------------------------------------
// Function:  sendSCSICommand()
//
// Input:   
//    char xdata *cmdbuf   - scsi command packet (EP2FIFOBUF + CBW_DATA_START)
//
// Output:  bit flag
//          0 = success, 1 = failure
//
// Local data:
//    WORD cmd_data - modified command data packet
//
// Description:
//    The command packet is sent to the drive using 16-bit register writes to
//    the drive's data register.  Data is modified to handle endian-ness before
//    before it is sent to the drive.
//
//    ALERT!!!:  Sending the command packet to the drive using register writes was
//       due to an assumption that we could not GPIF the middle of an endpoint's
//       content.  From SSW, we can walk down an endpoint's content using GPIF
//       as long as the transaction count is not exhausted.  For optimization,
//       we may want to GPIF the start of the CBW (maybe send it to the null
//       register where it won't cause grief), GPIF the scsi command packet
//       to the drive then discard the rest of the CBW.  This would remove the
//       need to process the command packet for endian-ness.
//-----------------------------------------------------------------------------
static bit sendSCSICommand()
{
   BYTE cmdLen = EP2FIFOBUF[CBW_CBW_LEN] & CBW_CBW_LEN_MASK;

   // Get ready for fast xfer (just in case)
   mymemmoveix(prevCmd,&EP2FIFOBUF[0x0F],12);
   prevDataTransferLen = dataTransferLen;
   // clear the fast flag.  Will be set within the UDMA routines.
   attemptFastScsi = 0;

   if (!bScsiRegsPreloaded)
      preloadSCSIRegs();

   // if the drive is configured for udma then use udma
   if (ActiveLunConfigData.udmaMode)
      bUseUdma = 1;     
   else
      bUseUdma = 0;

   if (EP2FIFOBUF[0xf] == INQUIRY)     // Manually process INQUIRY so we can modify the device string.
      bUseUdma = 0;

   if (!dataTransferLenLSW && !dataTransferLenMSW)
      bUseUdma = 0;

   if (directionIn && (dataTransferLenLSB & 1))
      bUseUdma = 0;

   if (!bUseUdma)
      writePIO8(ATAPI_FEATURE_REG, 0x00);    // Feature is ALWAYS set to UDMA mode in prepSCSICommand

   if (deviceCount != 1)
      {
      // Select ATAPI device
      writeATA_DRIVESEL_REG();
   
      // Make sure the device is ready for the packet
      while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
         ;
      }

   // Send the "ATAPI packet" command
   fastWritePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_ATAPI_PACKET);

//   if(driveStatus & ATAPI_STATUS_ERROR_BIT)
//      {
//      EP2BCL = 0x80;         // Release the endpoint buffer
//      return(USBS_FAILED);
//      }
   
   // Zero out non-command bytes
   {
   BYTE i;

   AUTOPTRH2 = MSB(EP2FIFOBUF+CBW_DATA_START);
   AUTOPTRL2 = LSB(EP2FIFOBUF+CBW_DATA_START+cmdLen);
   for (i = cmdLen; i < 12; i++)
      XAUTODAT2 = 0;
   }

   // Wait for the register block to be non-busy and to request data
   while( (readATAPI_STATUS_REG() & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_DRQ_BIT)) != ATAPI_STATUS_DRQ_BIT)
      ;

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // It may seem cumbersome to write out the SCSI command one word at a time when we could just move the block 
   // and use our block copy routine.  It turns out that moving the block takes LONGER than writing the data
   // in the manner used below (SYK 5/03)
   ////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Write 12 bytes of command
   AUTOPTRL2 = LSB(EP2FIFOBUF+CBW_DATA_START);
   {
      BYTE i;
      BYTE cmd_lsb;
   
      // for(i=0; i<12; i+=2)  structuring the loop backwards reminds the compiler to use DJNZ instruction

      // GPIF cannot be busy.  We just did a read.
      // Write the address/chip selects
      OUTATAPI = ATAPI_DATA_REG | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
      
      for(i = 6; i != 0; i--)
         {
         cmd_lsb = XAUTODAT2;

         // make sure GPIF is not busy
         while (!gpifIdle())
            {
            }
        
         // trigger the GPIF
         XGPIFSGLDATH = XAUTODAT2;                       // Single bus transaction on the GPIF
         XGPIFSGLDATLX = cmd_lsb;                   // Single bus transaction on the GPIF
         }  
    } 
   AUTOPTRH2 = MSB(EP6FIFOBUF);     // Restore Autoptr to the value that's used elsewhere.
   
   if (!bUseUdma)
   {
      WAIT_FOR_INTRQ();  
      
      if (waitForBusyBit() == USBS_FAILED)
         {
         EP2BCL = 0x80;         // Release the endpoint buffer
         return(USBS_FAILED);
         }

      #if ATAPI_WAIT_FOR_SERV_BIT
      // Wait for the register block to be non-busy and report SERV = 1.  
      for (driveStatus=ATAPI_STATUS_BUSY_BIT; (driveStatus & (ATAPI_STATUS_BUSY_BIT | 0x10)) != 0x10; )
         {
         // Read the alt status register so we don't trigger any events
         driveStatus = readPIO8(ATAPI_ALT_STATUS_REG);
         }
      #endif
   }

   EP2BCL = 0x80;         // Release the endpoint buffer
   return(USBS_PASSED);
}   

//-----------------------------------------------------------------------------
// Function:  scsiReadPio(BYTE cmd)
//
// Input:   BYTE -- Current command.  Needed so we can modify INQUIRY data received from the device.
// Output:  bit flag
//          0 = success, 1 = failure
//
// Global data:
//
// Local data:
//
// Description:
// Read from the drive until the drive is empty or the buffer is full.
// This breaks up the 16 bit length read into wPacketSize. driveDataLen is
// the amount of data available from the drive.  If the last read results in 
// a short packet, but the drive has more data to give, don't release the packet.
// until either the drive has finished or the packet is full.
//
// Phase error note:  In the Hi<>Do case, we will send garbage to the host before
// reporting the phase error.  In the Hi<Di case we return Di and report phase error.
//-----------------------------------------------------------------------------
BYTE scsiReadPio()
{

   BYTE driveStatus = 0;
   WORD wDriveDataLen = 0;
   WORD wReadLen = 0;       // Amount of data in the current transaction w/ the drive
   WORD wInSize = 0;        // Tracks the amount of data in the current IN packet
   bit bOddTransfer = 0;    // Compliance testing (not the real world) requires odd packet support.  
   bit bFirstPacket = 1;
   bit bDone = 0;
   bit cReturnStatus = USBS_PASSED;
   BYTE cmd = EP2FIFOBUF[0x0f];

   if (bOddTransfer = dataTransferLen & 1)      // = is intentional here!
      dataTransferLen++;

   while( (!(driveStatus & ATAPI_STATUS_ERROR_BIT)) && (!bDone) && dataTransferLen)
      {
      // Wait for an available buffer.
      waitForInBuffer();

      while( (wInSize < wPacketSize) && (!bDone) && dataTransferLen)
         {
         if(!wDriveDataLen)
            {
            // Wait for the register block to be non-busy and for the DRQ bit to be set.
            driveStatus = waitForDRQBit(1);
            readATAPI_STATUS_REG();             // Clear interrupt for next round.

            // Check if we're done or the drive still has data to transfer.
            if(driveStatus & ATAPI_STATUS_ERROR_BIT)
               {
               bDone = 1;
               cReturnStatus = USBS_FAILED;
               break;
               }
            else if(!(driveStatus & ATAPI_STATUS_DRQ_BIT) )
               {
               bDone=1;      // No more data
               cReturnStatus = USBS_PASSED;
               break;
               }
            else if (!(readPIO8(ATAPI_INT_CAUSE_REG) & 2))  // Check to see if the drive is trying to do IN our OUT (Hi <> Do)
               {
               bDone=1;      // No more data
               cReturnStatus = USBS_PHASE_ERROR;
               break;
               }
            else 
               wDriveDataLen = getDriveDataLen();
            }

         // Get data from drive to endpoint.
         wReadLen = min(wPacketSize-wInSize, wDriveDataLen);
         if (!dataTransferLenMSW)
            wReadLen = min(dataTransferLenLSW, wReadLen);      // added to cover Hi<Di case
         readPIO16(wReadLen);          // add 1 in case readLen is odd
   
         // Adjust counts.
         wDriveDataLen -= wReadLen;
         dataTransferLen -= wReadLen;
         wInSize += wReadLen;
         }

⌨️ 快捷键说明

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