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

📄 ide.c

📁 Cy68013的应用——USB2.0接口转IDE、CF卡接口
💻 C
📖 第 1 页 / 共 3 页
字号:
      {               
         BYTE pagenum;
         
         pagenum = EP2FIFOBUF[CBW_DATA_START+2] & 0x3F; // identify page (see p.141 SCSI 2ed.)
   
         EP2BCL = 0x80; // relinquish control of the bulk buffer occupied by the CBW

         sensePtr = senseOk;
         checkForMedia(1);
         if (sensePtr != senseOk)
            {
            failedIn();
            return(USBS_FAILED);
            }

         waitForInBuffer();
         
         if((pagenum != 0x05) && (pagenum != 0x3F)
             && (pagenum != 0x01) && (pagenum != 0x08) && (pagenum != 0x1B))
         { // only respond to requests for certain pages (the mandatory ones plus page 5)
            sensePtr = senseInvalidFieldInCDB;
            failedIn();
            return(USBS_FAILED);
         }
   
         // If one of the supported pages is requested, return the 8 byte Mode Parameter Header
         // plus a single 12 byte page. Only the Mode Data length (LSB) is significant in the
         // Mode Parameter Header. It has a Vendor Specific Medium Type Code in byte 2, and
         // a 1 bit WP Write Protect bit in byte 3 that are not initialized here.
         // Pages 0x01, and 0x08 do not have significant data - they are spoofed.
         // Page 0x1B has a TLUN field in byte 3 that is initialized to 1 (as per ISD).
         // Page 0x05 does contain information that is needed to boot to HDD and CDROM.
         // Page 0x3F, All Pages, is also responded to.
         // The supported pages are (see INF-8070_1_3.pdf p37 Table 25):
         //   case 0x01:                          // Read-Write Error Recovery Page
         //   case 0x08:                          // Caching Page
         //   case 0x05:                          // Flexible Disk Page: needed to boot from USB
         //   case 0x1B:                          // Removable Block Access Capabilities Page
         //   case 0x3F:                          // All (4) Pages
         
         // The format used is:
         //    Mode parameter header (4 or 8 bytes)
         //    Block descriptors (not supported)
         //    Mode page
         EP8FIFOBUF[0] = 0x00;
         mymemmovexx(EP8FIFOBUF+1, EP8FIFOBUF, 100-1); // clear buffer - <100 bytes in all responses

         AUTOPTRL2 = LSB(EP8FIFOBUF);
         if (cmd == MODE_SENSE_10)
            {
            XAUTODAT2 = MSB(0);
            if (pagenum == 0x3f)
               XAUTODAT2 = LSB(8-2 + 12*4);      // return 12 bytes for each page
            else
               XAUTODAT2 = LSB(8-2 + 12*1);      // return 12 bytes for each page
            AUTOPTRL2 = LSB(EP8FIFOBUF) + 8;     // The rest of the header is zeroes.  Start the pages at byte 8.     
            }
         else
            {
            if (pagenum == 0x3f)
               XAUTODAT2 = LSB(4-1 + 12*4);      // Header is 4 bytes long, data from each page is 12 bytes.
            else
               XAUTODAT2 = LSB(4-1 + 12*1);      
            AUTOPTRL2 = LSB(EP8FIFOBUF) + 4;          
            }

         if((pagenum == 0x05) || (pagenum == 0x3F))
            {  
            XAUTODAT2 = 5;               // fill out the page num - fields are all 0x0
            XAUTODAT2 = 12-2;            // set individual Page Length -- return 12 for all commands

            if(EZUSB_HIGHSPEED())
               {
               XAUTODAT2 = 0xFF;         // HS Transfer Rate (MSB) (field limited to 65Mb/Sec)
               XAUTODAT2 = 0xFF;         // HS Transfer Rate (LSB)
               }
            else
               {
               XAUTODAT2 = 0x2E;         // FS Transfer Rate (MSB) (12Mb/Sec) 
               XAUTODAT2 = 0xE0;         // FS Transfer Rate (LSB)
               }
            XAUTODAT2 = ActiveLunConfigData.NumHeads;        // #Heads
            XAUTODAT2 = ActiveLunConfigData.NumSectPerTrack; // #SectorsPerTrack
            XAUTODAT2 = (ATA_SECTOR_SIZE >>  8) & 0xff; // Data Bytes per sector (truncated)
            XAUTODAT2 = (ATA_SECTOR_SIZE >>  0) & 0xff; // Data Bytes per sector
            XAUTODAT2 = ActiveLunConfigData.NumCylindersMSB; // #Cyl MSB
            XAUTODAT2 = ActiveLunConfigData.NumCylindersLSB; // #Cyl LSB
            XAUTODAT2 = 0;
            XAUTODAT2 = 0;
            }
         if(pagenum == 0x1B || pagenum == 0x3f)
            {
            XAUTODAT2 = 0x1b;            // fill out the page num
            XAUTODAT2 = 12-2;            // set individual Page Length -- return 12 for all commands
            XAUTODAT2 = 0;
            XAUTODAT2 = 0x01;            // set TLUN = 1 for page 0x1B
            AUTOPTRL2 += 8;              // 8 zeroes too.
            }
         if(pagenum == 0x1 || pagenum == 0x3f)
            {
            XAUTODAT2 = 0x1;             // fill out the page num
            XAUTODAT2 = 12-2;            // set individual Page Length -- return 12 for all commands
            AUTOPTRL2 += 10;              // 10 zeroes too.
            }

         if(pagenum == 0x8 || pagenum == 0x3f)
            {
            XAUTODAT2 = 0x8;             // fill out the page num
            XAUTODAT2 = 12-2;            // set individual Page Length -- return 12 for all commands
            AUTOPTRL2 += 10;              // 10 zeroes too.
            }

         loadEP8BC(AUTOPTRL2);
         sensePtr = senseOk;
         return(USBS_PASSED);
      } // end case

      default:
      {
         // relinquish control of the bulk buffer occupied by the CBW
         EP2BCL = 0x80;     
         
         sensePtr = senseInvalidOpcode;
         failedIn();
         return(USBS_FAILED);
      }
   }
}   

bit generalIDEOutCommand()
{
   BYTE cmd;
   
   cmd = EP2FIFOBUF[0xf];  
   
   switch (cmd)
   {
      case WRITE_06:
      case WRITE_10:
      case WRITE_AND_VERIFY_10:
      {
         sensePtr = senseOk;
         checkForMedia(1);
         if (sensePtr == senseOk)
            {
            return(ideWriteCommand(cmd));
            }
         else
         {
            // relinquish control of the bulk buffer occupied by the CBW
            EP2BCL = 0x80;
            if (dataTransferLen)
               stallEP2OUT();

            return(USBS_FAILED);
         }
      }                
      ///////////////////////////////////////////////////////////
      // Spoofed commands
      case MODE_SELECT_06:    // Note that these are in BOTH the read and write areas in case they are sent with no data
      case MODE_SELECT_10:
      {
         bit bShortPacketReceived = 0;

      // relinquish control of the bulk buffer occupied by the CBW
         EP2BCL = 0x80;   
  
      // Toss away all of the data received with the command
         while (dataTransferLen && !bShortPacketReceived)
            {
            if(!(EP2CS & bmEPEMPTY))   
               {
               dataTransferLen -= EP2BC;
               if (EP2BC != wPacketSize)
                  bShortPacketReceived = 1;   
               EP2BCL = 0x80;
               }
            }
         
      // This command is allowed to have data.         
         sensePtr = senseOk;
         checkForMedia(1);
         
         if (sensePtr == senseOk)
            return(USBS_PASSED);
         else
            return(USBS_FAILED);
      }                
      default:
         // relinquish control of the bulk buffer occupied by the CBW
         EP2BCL = 0x80;     
         
         if (dataTransferLen)
            stallEP2OUT();
         sensePtr = senseInvalidOpcode;         
         return(USBS_FAILED);
         break;
   }
}   



void waitForInBuffer()
{
   while((EP8CS & bmEPFULL));   // Wait for an available buffer from the host

   return;
}   


static bit ideReadCommand(BYTE command)
{   
   BYTE driveStatus;
   WORD sectorcount; 
   BYTE i; 
   WORD wordCtr;

   if (command == VERIFY_10)
      dataTransferLen = (DWORD)((EP2FIFOBUF[CBW_DATA_START+7] << (8+9)) + EP2FIFOBUF[CBW_DATA_START+8]) << 9;  // Multiplying by ATA_SECTOR_SIZE takes 90 bytes more than this.

   switch (command)
      {
      case READ_06:   
         {
         ((BYTE *) &dwLBA)[0] = 0;
         ((BYTE *) &dwLBA)[1] = EP2FIFOBUF[CBW_DATA_START+1] & 0x1f;
         ((BYTE *) &dwLBA)[2] = EP2FIFOBUF[CBW_DATA_START+2];
         ((BYTE *) &dwLBA)[3] = EP2FIFOBUF[CBW_DATA_START+3];
         // relinquish control of the bulk buffer occupied by the CBW
         EP2BCL = 0x80;     
         break;
         }
      default:
         IDEPrepareForXfer();
      }

   // This loop breaks up the 32 bit length into 8 bits * sectors.
   // For example, a read of 0x10000 turns into 0x80 sectors.
   while (dataTransferLen)
   {
      sectorcount = stuffLBAandSector(1);
        
      if (!ActiveLunConfigData.udmaMode || (command == VERIFY_10) || (dataTransferLenLSW & 0x1ff))    // UDMA cannot handle sub-sector sized reads
      {
         // Execute the read command
         if (bExtAddrSupport)
            {
            if ((command == VERIFY_10))
               writePIO8(ATA_COMMAND_REG, ATA_COMMAND_VERIFY_10_EXT);
            else
               writePIO8(ATA_COMMAND_REG, ATA_COMMAND_READ_10_EXT);
            }
         else
            {
            if ((command == VERIFY_10))
               writePIO8(ATA_COMMAND_REG, ATA_COMMAND_VERIFY_10);
            else
               writePIO8(ATA_COMMAND_REG, ATA_COMMAND_READ_10);
            }

           
         // The verify command reads from the drive, but doesn't transfer data
         // to us.
         if ((command == VERIFY_10))     
         {
            if(waitForBusyBit() == USBS_FAILED)
               {
               loadSensePtrFromErrorRegister(1);
               dataTransferLen = 0;    // This command has no data but this loop uses dataTransferLen as a counter.
               return(USBS_FAILED);
               }
            else
               {
               if (sectorcount == 0x100)
                  dataTransferLenMSW -= 2;
               else
                  dataTransferLen = 0;
               continue;
               }
         }

         // Wait for drive non-busy before starting xfer
         while (readPIO8(ATAPI_ALT_STATUS_REG) & ATAPI_STATUS_BUSY_BIT)
            ;
         
         // set up for GPIF transfer - wordwide
         //EP8GPIFTCH = MSB(wPacketSize >> 1);     
         //EP8GPIFTCL = LSB(wPacketSize >> 1);
         
         while (sectorcount--)
         {
            // Wait for the drive to be non-busy and have either data or an error
            while (1)
            {
               driveStatus = readATAPI_STATUS_REG();                             
               if ((driveStatus & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_DRQ_BIT)) == ATAPI_STATUS_DRQ_BIT)
                  break;
               if ((driveStatus & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_ERROR_BIT)) == ATAPI_STATUS_ERROR_BIT)
                  break;
            }

            // If there's an error, the drive may still want to send us the data.
            if (driveStatus & ATAPI_STATUS_ERROR_BIT)
               {
               loadSensePtrFromErrorRegister(1);
               if (driveStatus & ATAPI_STATUS_DRQ_BIT)
                  for (wordCtr = 0; wordCtr < 0x100; wordCtr++)
                     readPIO8(ATAPI_DATA_REG);
               failedIn();
               return(USBS_FAILED);  
               }
            else
            {
               BYTE bLimit;
               WORD wThisPacketSize;

               if (wPacketSize == 0x40)
                  bLimit = 8;
               else 
                  bLimit = 1;
               for (i = 0; i < bLimit && dataTransferLen; i++)
               {
                  waitForInBuffer();

                  wThisPacketSize = min(wPacketSize, dataTransferLen);
                  readPIO16(ATAPI_DATA_REG, wThisPacketSize);
                  while (!gpifIdle())     // Wait for xfer to complete
                     ;
                  OUTATAPI = ATAPI_IDLE_VALUE;

                  EP8BCH = MSB(wThisPacketSize);   
                  EP8BCL = LSB(wThisPacketSize);
                  dataTransferLen -= wThisPacketSize; 
               }
               // Check for residue at the drive.  If it's there, read it all.
               if (i < bLimit || wThisPacketSize != wPacketSize)
               {
                  while (readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
                      readPIO8(ATAPI_DATA_REG);
                  // Now we have up to 511 bytes of crap in the FIFO.
                  // Wait for the IN endpoint to be empty, then reset the FIFO
                  while (!(EP8CS & bmEPEMPTY))
                     ;
                  FIFORESET = 8;
               }
            }
         }//while (sectorcount--)
      }
      else  // transfer is udma mode
      {
         initUdmaRead();
         if (bExtAddrSupport)
            writePIO8(ATAPI_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY_EXT);
         else
            writePIO8(ATAPI_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY);
         readUDMA((DWORD) sectorcount << 8);     // Words = sectors * 256

         // switch the EP back to manual mode
         EP8FIFOCFG = bmZEROLENIN | bmWORDWIDE;
         WRITEDELAY();
         IFCONFIG = IFCONFIG_DEFAULT;

⌨️ 快捷键说明

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