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

📄 scsi.c

📁 对SCSI设备进行字节访问的操作,只要适合SCSI标准,均可
💻 C
📖 第 1 页 / 共 2 页
字号:
         {
          // Make sure the data is already in the endpoint buffer
         if(!(EP2CS & (bmEPEMPTY | bmEPSTALL))) 
            {
            if (EP2BC & (wPacketSize - 1))
               bShortPacketReceived = 1;

            EP2BCL = 00;         // Release the endpoint buffer to FIFO.
   
            // Get the amount of data the drive is willing to accept
            if(!wDriveDataLen)
               wDriveDataLen = getDriveDataLen();
   
            wAmountSent = 0; 
            while( (wPacketSize > wAmountSent) && (!bDone) && dataTransferLen)
               {
               // 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.  
               writePIO16(ATAPI_DATA_REG, wAmountToWrite+1);
               dataTransferLen -= wAmountToWrite;
               wDriveDataLen -= wAmountToWrite;
               wAmountSent += wAmountToWrite;
   
               // Make sure the write is successful, otherwise get out. -- First wait for the busy bit to clear.
               while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
                  ;
   
               // Don't trust the first result after the busy bit goes away.  Read it again.
               // The DELL-07 CDRW has occasional problems if this is not done.
               driveStatus = readATAPI_STATUS_REG();
               
               if(driveStatus & ATAPI_STATUS_ERROR_BIT)
                  {
                  cReturnStatus = USBS_FAILED;  
                  bDone = 1;                    
                  }
               else
                  {
                  // Check if drive is finished with transaction.
                  if(!(driveStatus & ATAPI_STATUS_DRQ_BIT))
                     {
                     bDone=1;
                     cReturnStatus = USBS_PASSED;
                     }
                  else if(!wDriveDataLen)
                     wDriveDataLen = getDriveDataLen();
   
                  } // end else
               } // end while(within current packet)
            } // end if(data in endpoint buffer)
         } // end while(all data)
      } // end if (drive has data)

   // If the device still wants more data from the host at this point, it's a phase error (case 13)
   if ((readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT) || wDriveDataLen)
      cReturnStatus = (USBS_PHASE_ERROR);   

   // 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:   
//    bit useInterrupt     
//    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(char xdata *cmdbuf)
{

   BYTE driveStatus;
  
   prepareForATAPICommand();
   
   CLEAR_INTRQ;    // Clear the interrupt bit.
   
   // Make sure the device is ready for the packet
   while (readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
      ;
   
   // 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
   do
     driveStatus = readPIO8(ATAPI_STATUS_REG);
   while( driveStatus & ATAPI_STATUS_BUSY_BIT);
   
   if(driveStatus & ATAPI_STATUS_ERROR_BIT)
     return(USBS_FAILED);
   
   // Write 6 words of command
   {
   BYTE i;
   WORD cmd_data;

      for(i=0; i<12; i+=2)
         {
         cmd_data = (BYTE) (cmdbuf[i+1]);
         cmd_data = (cmd_data << 8) | (BYTE) (cmdbuf[i]);
         writePIO8(ATAPI_DATA_REG, cmd_data);
         }
   }
   
   if (useUdma)
      return(USBS_PASSED);

   {
     // Wait for the register block to be non-busy   
     for (driveStatus=ATAPI_STATUS_BUSY_BIT; driveStatus & ATAPI_STATUS_BUSY_BIT; )
         {
         // Read the alt status register so we don't trigger any events
         driveStatus = readPIO8(ATAPI_ALT_STATUS_REG);
         }
   }

   if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)  // Reading the status reg clears the interrupt
      return(USBS_FAILED);
   else
      return(USBS_PASSED);
}   



static void prepareForATAPICommand()
{


   // Select ATAPI device
   writePIO8(ATAPI_DRIVESEL_REG, 0xa0);

   // Make sure the device is ready for the packet
   while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
      ;

   // configure the transfer mode (PIO or UDMA) using the feature register
   if (useUdma)
   {
      writePIO8(ATAPI_FEATURE_REG, 0x01);
   }
   else
   {
      // This disables disconnect/reconnect, synchronous, overlapped and DMA features.
      writePIO8(ATAPI_FEATURE_REG, 0x00);
   }

   // Set "max byte count"
   writePIO8(ATAPI_BYTE_COUNT_LSB, 0xff);
   writePIO8(ATAPI_BYTE_COUNT_MSB, 0xff);

}



//-----------------------------------------------------------------------------
// Function:  inDataFromDrive()
//
// Input:   none
// 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.
//-----------------------------------------------------------------------------
static BYTE inDataFromDrive()
{

   BYTE driveStatus;
   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 bDone = 0;
   bit cReturnStatus = USBS_FAILED;

   // Clear the interrupt bit
   CLEAR_INTRQ;
 
   // See if drive is finished processing command and
   // is ready for data.
   do
       {
       driveStatus = readPIO8(ATAPI_STATUS_REG);
       }
   while( driveStatus & ATAPI_STATUS_BUSY_BIT );   // DO-WHILE!!!

   // If the drive doesn't have data for us, take off!
   if(!(driveStatus & ATAPI_STATUS_DRQ_BIT) )
      return (USBS_PASSED);

   while( (!(driveStatus & ATAPI_STATUS_ERROR_BIT)) && (!bDone) && dataTransferLen)
      {
      // Get the amount of data the drive is willing to accept
      if(!wDriveDataLen)
         wDriveDataLen = getDriveDataLen();

      // Wait for an available buffer.
      waitForInBuffer();

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

         // Wait for the register block to be non-busy
         while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
            ;
         
         // Don't trust the first result after the busy bit goes away.  Read it again.
         // The DELL-07 CDRW has occasional problems if this is not done.
         driveStatus = readATAPI_STATUS_REG();

         // Check if we're done or the drive still has data to transfer.
         if(driveStatus & ATAPI_STATUS_ERROR_BIT)
            {
            bDone = 1;
            cReturnStatus = USBS_FAILED;
            }

         else if(!(driveStatus & ATAPI_STATUS_DRQ_BIT) )
            {
            bDone=1;      // No more data
            cReturnStatus = USBS_PASSED;
            }

         else 
            if(!wDriveDataLen)
               wDriveDataLen = getDriveDataLen();
         }

      // We either have a full packet or we're at the last packet.
      // Release the buffer to the SIE and re-init packet byte count.

      EP8BCH = MSB(wInSize);
      EP8BCL = LSB(wInSize);
      if (wInSize < wPacketSize)
         bShortPacketSent = 1;
      wInSize = 0;
      }

   // If the device still says it has data ready for us, we're either in case
   // 7 (Hi<Di) or 8 (Hi <> Do).  Both are phase error cases.
   if ((readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT) || wDriveDataLen)
      return (USBS_PHASE_ERROR);
  
   return(cReturnStatus);
}   

static bit inDataFromDriveUdma()
{
   BYTE driveStatus;
   BYTE error;
   
   initUdmaRead();

   readUDMA((dataTransferLen + 1) >> 1);

   // If there's anything in the transfer count it's an error
   // This code doesn't handle partial transfers.  Any failure kills the entire xfer.
   if (! (GPIFTCMSW || GPIFTCLSW))
   {
      dataTransferLen = 0;
   }

   // switch the EP back to manual mode
   EP8FIFOCFG = 0x05;

   driveStatus = readATAPI_STATUS_REG();

   // Check if stall is needed
   if (dataTransferLenLSW & (wPacketSize - 1))
      bShortPacketSent = 1;

   if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
   {
      error = readPIO8(ATAPI_ERROR_REG);

      // Upper 4 bits of error contain sense key.  4 is the sense key for parity error
      if ((error & 0xf0) == 0x40)
      {
        // Allow up to a 10/1 error ratio.  If it gets above that, slow down or stop using UDMA.
         udmaErrorCount += 10;
         if (udmaErrorCount >= 20)
            {
            if (udmaMode == TRANSFER_MODE_UDMA4)
               {
               udmaMode = TRANSFER_MODE_UDMA2;
               configureATATransferMode(udmaMode);
               }
            else
               {
               udmaMode = 0;
               configureATATransferMode(PIO_MODE4);
               }
            udmaErrorCount = 0;
            }
      }
      return(USBS_FAILED);
   }
   else if (driveStatus & ATAPI_STATUS_DRQ_BIT)
      return(USBS_PHASE_ERROR);
   else
      {
      if (udmaErrorCount)
         udmaErrorCount--;

      return(USBS_PASSED);
      }
}
   

// Note:  This routine will never STALL the out pipe.
//        If dataTransferLen remains above 0, it will get stuck rather than stall.
static BYTE scsiWriteUdma()
{
   BYTE driveStatus;

   writeUDMA((dataTransferLen+1) >> 1);

   // If there's anything in the transfer count it's an error
   // This code doesn't handle partial transfers.  Any failure kills the entire xfer.
   if (! (GPIFTCMSW || GPIFTCLSW))
   {
      dataTransferLen = 0;
   }

   // Check status to clear interrupt.
   driveStatus = readATAPI_STATUS_REG();
   if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
      return(USBS_FAILED);
   else if (driveStatus & ATAPI_STATUS_DRQ_BIT)
      return(USBS_PHASE_ERROR);
   else
      return(USBS_PASSED);
}

////////////////////////////////////////////////////////////////////////////////////////
#endif      // DEVICE_TYPE_IS_SCSI
////////////////////////////////////////////////////////////////////////////////////////







⌨️ 快捷键说明

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