Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

IdeAta.c

Go to the documentation of this file.
00001 /*!     \file drivers/ata/IdeAta.c
00002  *      \brief IDE driver::ATA Protocol.
00003  *      \author Luca Giovacchini
00004  *      \date Last update: 2003-11-07
00005  *      \note Copyright (©) 2003 Luca Giovacchini
00006  *
00007  *      This driver is based on Atadrv by Hale Landis
00008  *      but it is completely rearranged for the minirighi32.
00009  *      \n
00010  *      <b>IMPORTANT!!!</b>\n
00011  *      Here you can find sub implementing tha ATA-Standard protocols.
00012  *      Each Hd command must be executed throught one of these
00013  *      protocols.
00014  *      Parameters meanings are command dependent.
00015  *      Refer to Ata-4 document to see what protocol to use for each
00016  *      command and the meaning of each parameter.
00017  *      Some protocols are not developed exactly as T13 says.
00018  *
00019  *      Read IdeDebug for Error Return Code Explain.
00020  */
00021 
00022 #include <const.h>
00023 #include <string.h>
00024 
00025 #include <arch/i386.h>
00026 #include <arch/mem.h>
00027 #include <arch/interrupt.h>
00028 
00029 #include <kernel/Ide.h>
00030 #include <kernel/IdeLow.h>
00031 #include <kernel/clock.h>
00032 #include <kernel/IdeTimer.h>
00033 #include <kernel/IdeDebug.h>
00034 #include <kernel/video.h>
00035 
00036 #include <kernel/IdeAta.h>
00037 
00038 extern IdeChannel_Struct * CurrentChannel;
00039 
00040 // ******************* IdeDeviceDetection *******************
00041 // This sub Detect if some sort of device/s exist 
00042 // in the selected ide channel, it support the single
00043 // device configuration see Ata-4 9.16.2
00044 // **********************************************************
00045 void IdeDeviceDetection (int Dev) 
00046 {
00047         byte Sc,Sn;
00048 
00049         // Select the device
00050         SetDevBit(Dev);
00051 
00052         // we must try to issue a command (ex. write and read a readable and writeable register)
00053         // See Ata-4 9.16.2
00054         
00055         // try to write some value (do not use 00 or FF)
00056         OutPortAta(CC_SECC, 0x55 );
00057         OutPortAta(CC_SECN, 0xaa );
00058         OutPortAta(CC_SECC, 0xaa );
00059         OutPortAta(CC_SECN, 0x55 );
00060         OutPortAta(CC_SECC, 0x55 );
00061         OutPortAta(CC_SECN, 0xaa );
00062    
00063         // read if last value are stored correctly
00064         Sc = InPortAta( CC_SECC );
00065         Sn = InPortAta( CC_SECN );
00066 
00067         if ( ( Sc == 0x55 ) && ( Sn == 0xaa ) )    
00068         {
00069                 // we think (but not sure) there is a device but we don't know what type                
00070                 CurrentChannel->Device[Dev].Type=CC_DEVTYPE_UNKN;
00071         }
00072         else
00073         {
00074                 // we think (but not sure) there isn't a device
00075                 CurrentChannel->Device[Dev].Type=CC_DEVTYPE_NONE;
00076         }
00077 }
00078 
00079 // ***************** IdeDeviceTypeDetection *****************
00080 // try to identify the type of device/s present
00081 // **********************************************************
00082 void IdeDeviceTypeDetection (int Dev)
00083 {
00084         byte Sc,Sn,Cl,Ch,St;
00085 
00086         if ( CurrentChannel->Device[Dev].Type != CC_DEVTYPE_NONE )
00087         {
00088                 SetDevBit(Dev);
00089 
00090                 Sc = InPortAta( CC_SECC );
00091                 Sn = InPortAta( CC_SECN );
00092                 if ( ( Sc == 0x01 ) && ( Sn == 0x01 ) ) 
00093                 {
00094                         Cl = InPortAta( CC_CYLL );
00095                         Ch = InPortAta( CC_CYLH );
00096                         St = InPortAta( CC_STAT );
00097                         if ( ( Cl == 0x14 ) && ( Ch == 0xEB ) )
00098                                 CurrentChannel->Device[Dev].Type=CC_DEVTYPE_ATAPI;
00099                         else if ( ( Cl == 0x00 ) && ( Ch == 0x00 ) && ( St != 0x00 ) )
00100                                 CurrentChannel->Device[Dev].Type=CC_DEVTYPE_ATA;
00101                         else
00102                                 CurrentChannel->Device[Dev].Type=CC_DEVTYPE_UNKN;       
00103                 }
00104                 else
00105                         CurrentChannel->Device[Dev].Type=CC_DEVTYPE_NONE;
00106         }
00107 }
00108 
00109 
00110 // ********************* IdeSoftReset ***********************
00111 // Execute a SoftReset protocol (on the channel), after that
00112 // we must wait for device/s previouslt found to be ready
00113 // See ATA-2 Section 9.2, ATA-3 Section 9.2, ATA-4 Section 9.3
00114 // Errors int his sub are not critical
00115 // **********************************************************
00116 int IdeSoftReset( int SkipFlag, int UseInterrupt ) 
00117 {
00118         byte Sc,Sn,DevCtrl;
00119         byte Status;
00120         int Err1=FALSE;
00121         int Err2=FALSE;
00122         int Err3=FALSE;
00123         Timer_Struct Timer;
00124 
00125         // setup register values
00126         DevCtrl = HDC_DEVC_HD15 | ( UseInterrupt ? 0 : HDC_DEVC_NIEN );
00127 
00128         // initialize the command timeout counter
00129         Timer=TimerStart(HDC_ATATIMEOUT);
00130 
00131         // Set and then reset the soft reset bit in the Device Control register.
00132         // for at least x Ns (x may change with Ata version)
00133         // This causes device 0 be selected   
00134         // and both device initiate reset protocol.
00135         // Both Device shall be ready within 31 s
00136         if ( ! SkipFlag )
00137         {
00138                 OutPortAta( CC_DEVC, DevCtrl | HDC_DEVC_SRST );
00139                 DELAY400NS;
00140                 OutPortAta( CC_DEVC, DevCtrl );
00141                 DELAY400NS;
00142         }
00143         
00144 
00145         // If there is a device 0, wait for device 0 to set BSY=0.
00146         if ( CurrentChannel->Device[CC_DEV0].Type != CC_DEVTYPE_NONE ) 
00147         {
00148                 AtapiDelay(CC_DEV0);
00149                 if (WaitForBsy(Timer,CC_STAT))
00150                         Err1=TRUE;
00151         }       
00152         
00153 
00154         // If there is a device 1, wait until device 1 allows
00155         // register access.
00156         if ( CurrentChannel->Device[CC_DEV1].Type != CC_DEVTYPE_NONE ) {
00157                 AtapiDelay(CC_DEV1);
00158 
00159                 while ( TRUE )
00160                 {
00161                         SetDevBit(CC_DEV1);
00162 
00163                         Sc = InPortAta( CC_SECC );
00164                         Sn = InPortAta( CC_SECN );
00165                         if ( ( Sc == 0x01 ) && ( Sn == 0x01 ) )
00166                                 break;
00167 
00168                         if ( TimerElapsed(Timer) )
00169                         {
00170                                 Err2=TRUE;              
00171                                 break;
00172                         }
00173                         GoIdle();
00174                 }
00175 
00176                 // Now check if drive 1 set BSY=0.
00177                 if ( !Err1 && !Err2 ) 
00178                 {
00179                         Status=InPortAta( CC_STAT );
00180                         if ( Status & HDC_STAT_BSY )
00181                                 Err3=TRUE;
00182                 }
00183         }       
00184 
00185         // RESET_DONE:
00186         SetFirstDevBit();       
00187 
00188         if (Err3)
00189                 return 3;
00190         else if (Err1 && Err2)
00191                 return 4;
00192         else if (Err2)
00193                 return 2;
00194         else if (Err1)
00195                 return 1;
00196                 
00197         return 0;
00198 }
00199 
00200 // ******************* IdeDeviceSelection *******************
00201 // Execute Selection Device Protocol (see Ata-4 9.6)
00202 // Before issue a NonData, DataIn or DataOut protocol for
00203 // a particular device we must wait device to be ready
00204 // This is a little different from ata-4 in signal checked
00205 // **********************************************************
00206 int IdeDeviceSelection( int Dev )
00207 {
00208         byte Status;
00209         Timer_Struct Timer;
00210 
00211         // PAY ATTENTION HERE
00212         // The caller may want to issue a command to a device that doesn't
00213         // exist (for example, Exec Dev Diag), so if we see this,
00214         // just select that device, skip all status checking and return.
00215         // We assume the caller knows what they are doing!
00216 
00217         if ( CurrentChannel->Device[Dev].Type != CC_DEVTYPE_ATA && CurrentChannel->Device[Dev].Type != CC_DEVTYPE_ATAPI )
00218         {
00219                 // select the device and return
00220                 SetDevBit(Dev);
00221                 return 0; 
00222         }
00223 
00224         Timer=TimerStart(HDC_ATATIMEOUT);
00225    // The rest of this is the normal ATA stuff for device selection
00226    // and we don't expect the caller to be selecting a device that
00227    // does not exist.
00228    // We don't know which drive is currently selected but we should
00229    // wait for it to be not BUSY.  Normally it will be not BUSY
00230    // unless something is very wrong!
00231         if (WaitForBsy(Timer,CC_STAT))  
00232                 return 11;              
00233 
00234    // Here we select the drive we really want to work with by
00235    // putting 0xA0 or 0xB0 in the Drive/Head register (1f6).
00236         SetDevBit(Dev);
00237 
00238    // If the selected device is an ATA device,
00239    // wait for it to have READY and SEEK COMPLETE
00240    // status.  Normally the drive should be in this state unless
00241    // something is very wrong (or initial power up is still in
00242    // progress).  For any other type of device, just wait for
00243    // BSY=0 and assume the caller knows what they are doing.
00244 
00245         while ( TRUE )
00246         {
00247                 Status = InPortAta( CC_STAT );
00248                 if ( CurrentChannel->Device[Dev].Type == CC_DEVTYPE_ATA )
00249                 {
00250                         if ( ( Status & ( HDC_STAT_BSY | HDC_STAT_RDY | HDC_STAT_SKC ) )
00251                                                 == ( HDC_STAT_RDY | HDC_STAT_SKC ) )
00252                                 break;
00253                 }
00254                 else
00255                 {
00256                         if ( ( Status & HDC_STAT_BSY ) == 0 )
00257                     break;
00258                 }
00259                 if ( TimerElapsed(Timer) )
00260                         return 12;
00261         }
00262 
00263         return 0;
00264 }
00265 
00266 // *********************** IdeNonData ***********************
00267 // NonData Command Protocol See Ata-4 9.9 for a complete list
00268 // of command executable with this protocol
00269 // **********************************************************
00270 int IdeNonData( int Dev, int Cmd,
00271                    int Feat, int SecC,
00272                    dword Cyl, int Head, int Sect, int UseInterrupt )
00273 {
00274         byte SecCnt;
00275         byte SecNum;
00276         byte DevHead;
00277         byte DevCtrl;
00278         byte CylLow;
00279         byte CylHigh;
00280         byte Status;
00281         int TimeOut=FALSE;
00282         int Err=FALSE;
00283         Timer_Struct Timer;
00284 
00285         DevCtrl = HDC_DEVC_HD15 | (UseInterrupt ? 0 : HDC_DEVC_NIEN);
00286         DevHead = CurrentChannel->Device[Dev].RegBit;
00287         DevHead = DevHead | ( Head & 0x4f );
00288         CylLow = Cyl & 0x00ff;
00289         CylHigh = ( Cyl & 0xff00 ) >> 8;
00290 
00291 
00292         Timer=TimerStart(HDC_ATATIMEOUT);
00293 
00294         if ( Cmd != HDC_CMD_DEVICE_RESET )
00295         {
00296                 // Select the drive - call the sub_select function.
00297                 // Quit now if this fails.
00298 
00299                 Err=IdeDeviceSelection(Dev);
00300                 if ( Err )
00301                         return Err;
00302 
00303                 // Set up all the registers except the command register.
00304 
00305                 OutPortAta( CC_DEVC, DevCtrl );
00306                 OutPortAta( CC_FEAT, Feat );
00307                 OutPortAta( CC_SECC, SecC );
00308                 OutPortAta( CC_SECN, Sect );
00309                 OutPortAta( CC_CYLL, CylLow );
00310                 OutPortAta( CC_CYLH, CylHigh );
00311                 OutPortAta( CC_DEVH, DevHead );
00312         }
00313 
00314 
00315         OutPortAta( CC_CMD, Cmd );
00316         DELAY400NS;
00317 
00318         AtapiDelay(CC_DEV0);
00319         AtapiDelay(CC_DEV1);    
00320 
00321         if ( ( Cmd == HDC_CMD_EXECUTE_DEVICE_DIAGNOSTIC ) &&
00322        ( CurrentChannel->Device[CC_DEV0].Type == CC_DEVTYPE_NONE ) )
00323         {
00324     
00325                 while ( TRUE )
00326                 {
00327                         OutPortAta( CC_DEVH, HDC_DEVH_DEV1 );
00328                         DELAY400NS;
00329                         SecCnt = InPortAta( CC_SECC );
00330                         SecNum = InPortAta( CC_SECN );
00331                         if ( ( SecCnt == 0x01 ) && ( SecNum == 0x01 ) )
00332                                 break;
00333                         if ( TimerElapsed(Timer) )
00334                         {
00335                                 Err=24;
00336                                 break;
00337                         }
00338                 }
00339         }
00340         else
00341         {               
00342                 if ( Cmd == HDC_CMD_DEVICE_RESET || !UseInterrupt )
00343                 {
00344                         TimeOut=WaitForBsy(Timer,CC_ASTAT);
00345                         Err=23;
00346                 }
00347                 else
00348                 {
00349                         TimeOut=WaitForInt(Timer);
00350                         Err=22; 
00351                 }
00352         }
00353         // We MUST read status register even if we have a timeout
00354         // for clear pending interrupt
00355         // Read the primary status register.  In keeping with the rules
00356         // stated above the primary status register is read only
00357         // ONCE.
00358         Status = InPortAta( CC_STAT );
00359 
00360         // Error if BUSY, DEVICE FAULT, DRQ or ERROR status now.
00361 
00362         if (Err)
00363                 return Err;
00364 
00365         if ( Status & ( HDC_STAT_BSY | HDC_STAT_DF | HDC_STAT_DRQ | HDC_STAT_ERR ) ) 
00366                 return 21;
00367 
00368         return 0;
00369 }
00370 
00371 // ******************** IdePioDataInLba *********************
00372 // Decompose Lba 48-bit to be used in Cyl Head Sect Register
00373 // THIS IS NOT A LBA2CHS TRANSLATION BUT A DECOMPOSITION
00374 // OF 48 BIT IN 16+16+16, See IdePioDataIn Coment
00375 // **********************************************************
00376 int IdePioDataInLba(int Dev, int Cmd,
00377                                         int Feat, int SecC, uint64 Lba,
00378                                         word * Buffer,
00379                                         int NumSect, int MultiCnt, int UseInterrupt)
00380 {
00381         dword Cyl;
00382         int Head, Sect;
00383 
00384         // Decompose Lba part for Sector register
00385         Sect = (int) ( Lba & 0x000000ffL );
00386         Lba = Lba >> 8;
00387         // Decompose lba part for Cylinder register
00388         Cyl = (int) ( Lba & 0x0000ffff );
00389         Lba = Lba >> 16;
00390         // Decompose last part of lba address to be used in Head 
00391         // register and set the bit to indicate that this is Lba
00392         // and not head number
00393         Head = ( (int) ( Lba & 0x0fL ) ) | HDC_DEVH_LBA;
00394         // Call Chs function with value meaning Lba address
00395         return IdePioDataIn( Dev, Cmd, Feat, SecC,
00396                          Cyl, Head, Sect, Buffer,
00397                          NumSect, MultiCnt, UseInterrupt);
00398 }
00399 
00400 // ********************** IdePioDataIn **********************
00401 // Execute the PioDataIn protocol, this must be used for 
00402 // all PioDataIn Command (see Ata-4 9.7) such as IdentifyDevice.
00403 // Parameter and Register are Command Dependent so they need a
00404 // little explain
00405 // Command like Identify Device want Sect = 0
00406 // But they transfer a "sector" from hd, this is why NumSec is 1
00407 // Command like ReadSector Transfer X Sector so
00408 // Sect=x, and NumSect=x
00409 // Sect : Number of sector to transfer from hd
00410 // NumSect : Number of 256 word to transfer from hd buffer
00411 // MultiCnt : Sector per block in ReadMultiple
00412 // **********************************************************
00413 int IdePioDataIn(   int Dev, int Cmd,
00414                                         int Feat, int SecC,
00415                     dword Cyl, int Head, int Sect,
00416                     word * Buffer,
00417                     int NumSect, int MultiCnt, int UseInterrupt)
00418 {
00419         byte DevHead;
00420         byte DevCtrl;
00421         byte CylLow;
00422         byte CylHigh;
00423         byte Status;
00424         dword WordCnt=0;
00425         int TimeOut=FALSE;
00426         int Err=FALSE;
00427         Timer_Struct Timer;
00428         
00429         // setup register values and adjust parameters
00430         DevCtrl = HDC_DEVC_HD15 | (UseInterrupt ? 0 : HDC_DEVC_NIEN);
00431         DevHead = CurrentChannel->Device[Dev].RegBit;
00432         // with 4f i let pass head number and lba bit
00433         DevHead = DevHead | ( Head & 0x4f );
00434         CylLow = Cyl & 0x00ff;
00435         CylHigh = ( Cyl & 0xff00 ) >> 8;
00436 
00437         // these commands transfer only 1 sector
00438         if (    ( Cmd == HDC_CMD_IDENTIFY_DEVICE )
00439                         || ( Cmd == HDC_CMD_IDENTIFY_PACKET_DEVICE )
00440                         || ( Cmd == HDC_CMD_READ_BUFFER )
00441                 )
00442 
00443                 NumSect = 1;
00444 
00445         if ( Cmd != HDC_CMD_READ_MULTIPLE )
00446                 MultiCnt=1;
00447         
00448         // Set command time out.
00449         Timer=TimerStart(HDC_ATATIMEOUT);
00450 
00451         //Select device if it is not busy
00452         Err=IdeDeviceSelection( Dev );
00453         if ( Err )
00454                 return Err;     
00455 
00456         // Set up all the registers except the command register.
00457         OutPortAta( CC_DEVC, DevCtrl );
00458         OutPortAta( CC_FEAT, Feat );
00459         OutPortAta( CC_SECC, SecC );
00460         OutPortAta( CC_SECN, Sect );
00461         OutPortAta( CC_CYLL, CylLow );
00462         OutPortAta( CC_CYLH, CylHigh );
00463         OutPortAta( CC_DEVH, DevHead );
00464         
00465         // Start the command by setting the Command register.  The drive
00466         // should immediately set BUSY status.
00467         CurrentChannel->IntDone = FALSE;
00468         OutPortAta(CC_CMD,Cmd); 
00469         
00470         // We MUST waste some time by reading the alternate status a few times,
00471         // for gives drive the time to set BUSY in the status register (400ns).
00472         DELAY400NS;
00473 
00474         // Loop to read each sector.
00475         while ( TRUE )
00476         {
00477                 // NOTE NOTE NOTE ...  The primary status register (1f7) MUST NOT be
00478                 // read more than ONCE for each sector transferred!  When the
00479                 // primary status register is read, the drive resets IRQ 14.  The
00480                 // alternate status register (3f6) can be read any number of times.
00481                 // After INT 7x read the the primary status register ONCE
00482                 // and transfer the 256 words (REP INSW).  AS SOON as BOTH the
00483                 // primary status register has been read AND the last of the 256
00484                 // words has been read, the drive is allowed to generate the next
00485                 // IRQ 14 (newer and faster drives could generate the next IRQ 14 in
00486                 // 50 microseconds or less).  If the primary status register is read
00487                 // more than once, there is the possibility of a race between the
00488                 // drive and the software and the next IRQ 14 could be reset before
00489                 // the system interrupt controller sees it.
00490 
00491                 // Wait for INT or wait for not BUSY or wait for time out.
00492 
00493                 AtapiDelay(Dev);
00494 
00495                 if (UseInterrupt)
00496                         TimeOut=WaitForInt(Timer);
00497                 else
00498                         TimeOut=WaitForBsy(Timer,CC_ASTAT);
00499 
00500 
00501                 // Read the primary status register even if there was a timeout
00502                 // to clear pending interrupt.  
00503                 // In keeping with the rules stated above the primary status
00504                 // register is read only ONCE.
00505                 Status = InPortAta( CC_STAT );
00506 
00507 
00508                 if (TimeOut)
00509                         return ( UseInterrupt ? 34 : 35);
00510 
00511 
00512                 // If BSY=0 and DRQ=1, transfer the data,
00513                 // even if we find out there is an error later.
00514                 if ( ( Status & ( HDC_STAT_BSY | HDC_STAT_DRQ ) ) == HDC_STAT_DRQ )
00515                 {
00516                         // determine the number of sectors to transfer
00517                         // MultiCnt is >1 only on Read Multiple command
00518                         // Read Multiple need that we use Set Multiple to
00519                         // indicate numsect per block to transfer. An interrupt
00520                         // is sent only after each block and not after each sector
00521                         WordCnt = MultiCnt ? MultiCnt : 1;
00522                         if ( WordCnt > NumSect )
00523                                 WordCnt = NumSect;
00524                         WordCnt = WordCnt * 256;
00525 
00526                         // A sector is 512 byte or 256 word                     
00527                         // Do the REP INSW to read the data for one block.
00528                         InPortAtaMul(CC_DATA,Buffer,WordCnt);
00529 
00530                         DELAY400NS;    // delay so device can get the status updated
00531 
00532                         // Note: The drive should have dropped DATA REQUEST by now.  If there
00533                         // are more sectors to transfer, BUSY should be active now (unless
00534                         // there is an error).
00535 
00536                         // Decrement the count of sectors to be transferred
00537                         // and increment buffer address.
00538                         NumSect = NumSect - 1;
00539 
00540                         Buffer+=WordCnt;                        
00541                 }
00542                 else
00543                         return 32;                      
00544 
00545                 // So was there any error condition?
00546                 if ( Status & ( HDC_STAT_BSY | HDC_STAT_DF | HDC_STAT_ERR ) )
00547                         return 31;
00548 
00549                 // DRQ should have been set -- was it?
00550                 if ( ( Status & HDC_STAT_DRQ ) == 0 )
00551                         return 32;                      
00552 
00553                 // If all of the requested sectors have been transferred, make a
00554                 // few more checks before we exit.
00555                 if ( NumSect < 1 )
00556                 {
00557                         // Since the drive has transferred all of the requested sectors
00558                         // without error, the drive should not have BUSY, DEVICE FAULT,
00559                         // DATA REQUEST or ERROR active now.
00560                         AtapiDelay(Dev);
00561 
00562                         Status = InPortAta( CC_STAT );
00563                         if ( Status & ( HDC_STAT_BSY | HDC_STAT_DF | HDC_STAT_DRQ | HDC_STAT_ERR ) )
00564                                 return 33;
00565 
00566                         // All sectors have been read without error
00567                         break;   
00568                 }
00569 
00570       // This is the end of the read loop.  If we get here, the loop is
00571       // repeated to read the next sector.  Go back 
00572         }
00573         
00574         return 0;
00575 }
00576 
00577 
00578 // ******************** IdePioDataOutLba *********************
00579 // Decompose Lba 48-bit to be used in Cyl Head Sect Register
00580 // THIS IS NOT A LBA2CHS TRANSLATION BUT A DECOMPOSITION
00581 // OF 48 BIT IN 16+16+16, See IdePioDataOut Coment
00582 // **********************************************************
00583 int IdePioDataOutLba(int Dev, int Cmd,
00584                                         int Feat, int SecC, uint64 Lba,
00585                                         word * Buffer,
00586                                         int NumSect, int MultiCnt, int UseInterrupt)
00587 {
00588         dword Cyl;
00589         int Head, Sect;
00590 
00591         // Decompose Lba part for Sector register
00592         Sect = (int) ( Lba & 0x000000ffL );
00593         Lba = Lba >> 8;
00594         // Decompose lba part for Cylinder register
00595         Cyl = (int) ( Lba & 0x0000ffff );
00596         Lba = Lba >> 16;
00597         // Decompose last part of lba address to be used in Head 
00598         // register and set the bit to indicate that this is Lba
00599         // and not head number
00600         Head = ( (int) ( Lba & 0x0fL ) ) | HDC_DEVH_LBA;
00601         // Call Chs function with value meaning Lba address
00602         return IdePioDataOut( Dev, Cmd, Feat, SecC,
00603                          Cyl, Head, Sect, Buffer,
00604                          NumSect, MultiCnt, UseInterrupt);
00605 }
00606 
00607 // ********************** IdePioDataOut *********************
00608 // Execute the PioDataOut protocol, this must be used for 
00609 // all PioDataOut Command (see Ata-4 9.8)
00610 // See also IdePioDataIn Comment
00611 // **********************************************************
00612 int IdePioDataOut(  int Dev, int Cmd,
00613                                         int Feat, int SecC,
00614                     dword Cyl, int Head, int Sect,
00615                     word * Buffer,
00616                     int NumSect, int MultiCnt, int UseInterrupt)
00617 {
00618         byte DevHead;
00619         byte DevCtrl;
00620         byte CylLow;
00621         byte CylHigh;
00622         byte Status;
00623         int TimeOut=FALSE;
00624         int loopFlag = TRUE;
00625         dword WordCnt;
00626         int Err=FALSE;
00627         Timer_Struct Timer;
00628 
00629         // setup register values and adjust parameters
00630         DevCtrl = HDC_DEVC_HD15 | ( UseInterrupt ? 0 : HDC_DEVC_NIEN );
00631         DevHead = CurrentChannel->Device[Dev].RegBit;
00632         // with 4f i let pass head number and lba bit
00633         DevHead = DevHead | ( Head & 0x4F );
00634         CylLow = Cyl & 0x00FF;
00635         CylHigh = ( Cyl & 0xFF00 ) >> 8;
00636         // these commands transfer only 1 sector
00637         if ( Cmd == HDC_CMD_WRITE_BUFFER )
00638                 NumSect = 1;
00639         // only Write Multiple and CFA Write Multiple W/O Erase uses multCnt
00640         if (    ( Cmd != HDC_CMD_WRITE_MULTIPLE )
00641                 && ( Cmd != HDC_CMD_CFA_WRITE_MULTIPLE_WO_ERASE )
00642                 )
00643                 MultiCnt = 1;
00644 
00645         // Set command time out.
00646         TimerStart(HDC_ATATIMEOUT);
00647 
00648         //Select device if it is not busy 
00649         Err=IdeDeviceSelection( Dev );
00650         if ( Err )
00651                 return Err;
00652 
00653         // Set up all the registers except the command register.
00654         OutPortAta( CC_DEVC, DevCtrl );
00655         OutPortAta( CC_FEAT, Feat );
00656         OutPortAta( CC_SECC, SecC );
00657         OutPortAta( CC_SECN, Sect );
00658         OutPortAta( CC_CYLL, CylLow );
00659         OutPortAta( CC_CYLH, CylHigh );
00660         OutPortAta( CC_DEVH, DevHead );
00661 
00662         // Start the command by setting the Command register.  The drive
00663         // should immediately set BUSY status.
00664         CurrentChannel->IntDone = FALSE;
00665         OutPortAta(CC_CMD,Cmd); 
00666 
00667         // We MUST waste some time by reading the alternate status a few times,
00668         // for gives drive the time to set BUSY in the status register (400ns).
00669         DELAY400NS;
00670 
00671         // Wait for not BUSY or time out. 
00672         // NOTE: No interrupt is generated for the first sector of a write
00673         // command.  Well... that's not really true we are working with
00674         // a PCMCIA PC Card ATA device.
00675         AtapiDelay(Dev);        
00676         
00677         if ( WaitForBsy(Timer,CC_ASTAT) )
00678                 return 47;
00679         
00680         // Need to know the current status inside the while
00681         // (i use astat because it not reset interrupt)
00682         Status=InPortAta(CC_ASTAT);
00683 
00684         // If we are using interrupts and we just got an interrupt, this is
00685         // wrong.  The drive must not generate an interrupt at this time.
00686         if ( loopFlag && ( UseInterrupt && CurrentChannel->IntDone ) )
00687                 return 46;
00688         
00689         // This loop writes each sector.
00690         while ( loopFlag )
00691         {
00692                 // NOTE NOTE NOTE ...  The primary status register (1f7) MUST NOT be
00693                 // read more than ONCE for each sector transferred!  When the
00694                 // primary status register is read, the drive resets IRQ 14.  The
00695                 // alternate status register (3f6) can be read any number of times.
00696                 // For correct results, transfer the 256 words (REP OUTSW), wait for
00697                 // INT and then read the primary status register.  AS
00698                 // SOON as BOTH the primary status register has been read AND the
00699                 // last of the 256 words has been written, the drive is allowed to
00700                 // generate the next IRQ 14 (newer and faster drives could generate
00701                 // the next IRQ 14 in 50 microseconds or less).  If the primary
00702                 // status register is read more than once, there is the possibility
00703                 // of a race between the drive and the software and the next IRQ 14
00704                 // could be reset before the system interrupt controller sees it.
00705 
00706                 // If BSY=0 and DRQ=1, transfer the data,
00707                 // even if we find out there is an error later.
00708 
00709                 if ( ( Status & ( HDC_STAT_BSY | HDC_STAT_DRQ ) ) == HDC_STAT_DRQ )
00710                 {
00711                         // determine the number of sectors to transfer
00712 
00713                         WordCnt = MultiCnt ? MultiCnt : 1;
00714                         if ( WordCnt > NumSect )
00715                                 WordCnt = NumSect;
00716                         WordCnt = WordCnt * 256;
00717 
00718                         // Do the REP OUTSW to write the data for one block.
00719                         OutPortAtaMul( CC_DATA, Buffer,WordCnt );
00720 
00721                         DELAY400NS;    // delay so device can get the status updated
00722 
00723                         // Note: The drive should have dropped DATA REQUEST and
00724                         // raised BUSY by now.
00725 
00726                         // Decrement the count of sectors to be transferred
00727                         // and increment buffer address.
00728                         NumSect = NumSect - ( MultiCnt ? MultiCnt : 1 );
00729                         Buffer+=WordCnt;
00730                 }
00731                 else
00732                         return 42;
00733 
00734                 // So was there any error condition?
00735                 if ( Status & ( HDC_STAT_BSY | HDC_STAT_DF | HDC_STAT_ERR ) )
00736                         return 41;
00737 
00738                 // DRQ should have been set -- was it?
00739                 if ( ( Status & HDC_STAT_DRQ ) == 0 )
00740                         return 42;
00741 
00742                 AtapiDelay(Dev);
00743 
00744                 // if there was a timeout we must read the status register
00745                 // to clear pending interrupt before exit
00746                 if ( UseInterrupt )
00747                         TimeOut=WaitForInt(Timer);
00748                 else
00749                         TimeOut=WaitForBsy(Timer,CC_ASTAT);
00750 
00751 
00752                 // Read the primary status register.  In keeping with the rules
00753                 // stated above the primary status register is read only ONCE.
00754                 if ( TimeOut )
00755                         return ( UseInterrupt ? 44 : 45);
00756 
00757                 // If all of the requested sectors have been transferred, make a
00758                 // few more checks before we exit.
00759 
00760                 if ( NumSect < 1 )
00761                 {
00762                         // Since the drive has transferred all of the sectors without
00763                         // error, the drive MUST not have BUSY, DEVICE FAULT, DATA REQUEST
00764                         // or ERROR status at this time.
00765 
00766                         if ( Status & ( HDC_STAT_BSY | HDC_STAT_DF | HDC_STAT_DRQ | HDC_STAT_ERR ) )
00767                                 return 43;
00768 
00769                         // All sectors have been written without error, go to WRITE_DONE.
00770 
00771                         break;
00772 
00773                 }
00774 
00775         
00776                 // This is the end of the write loop.  If we get here, the loop
00777                 // is repeated to write the next sector.  Go back
00778         }
00779 
00780         return 0;
00781 }
00782 

Generated on Fri Feb 20 15:32:15 2004 for Minirighi by doxygen1.2.18