ATA Demo.c

/*
    File:       ATA Demo.c
    
    Description:ATADemo is a CodeWarrior C sample that will call the ATA
                Manager and scan the ATA bus and list the various device
                configuration data.  
     
                This sample has been updated to properly work with the .AppleCD
                driver installed.
 
                The sample also has been updated to attempt to read sector 0 of
                each ATA or ATAPI device and display the contents. 
                
    Copyright:  © Copyright 1996-2001 Apple Computer, Inc. All rights reserved.
    
    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
                ("Apple") in consideration of your agreement to the following terms, and your
                use, installation, modification or redistribution of this Apple software
                constitutes acceptance of these terms.  If you do not agree with these terms,
                please do not use, install, modify or redistribute this Apple software.
 
                In consideration of your agreement to abide by the following terms, and subject
                to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
                copyrights in this original Apple software (the "Apple Software"), to use,
                reproduce, modify and redistribute the Apple Software, with or without
                modifications, in source and/or binary forms; provided that if you redistribute
                the Apple Software in its entirety and without modifications, you must retain
                this notice and the following text and disclaimers in all such redistributions of
                the Apple Software.  Neither the name, trademarks, service marks or logos of
                Apple Computer, Inc. may be used to endorse or promote products derived from the
                Apple Software without specific prior written permission from Apple.  Except as
                expressly stated in this notice, no other rights or licenses, express or implied,
                are granted by Apple herein, including but not limited to any patent rights that
                may be infringed by your derivative works or by other works in which the Apple
                Software may be incorporated.
 
                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
                COMBINATION WITH YOUR PRODUCTS.
 
                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
        
    Change History (most recent first):
        04/04/01    Converted to CW Pro 6
                    Added file ATAExecIO.c to demonstrate sending ATA and ATAPI commands
                    Read and display sector 0 of each device <JAS>
                    
        06/23/99    Reformatted and Recompiled on CW Pro 2.1(KG)
        
        03/15/99    Updated to CW 4 and it's headers.
                    Added code to set the standard .AppleCD driver
                    into a quiescent state and thus allow us to
                    query the ATA bus without disturbing the .AppleCD driver.(VM)
                        
        06/25/98    Buffer was still the incorrect size in 
                    DisplayATADriveIdentity routine.
                    Buffer needs to be 256 words (for 512 bytes long). 
                    Drive identify just assumes you have allocated a
                    512 byte buffer and writes it accordingly.  In
                    this case it overwrites the end of the array.
 
                    Modified to CW Pro 3 and its headers(VM)
 
 
        10/05/97    Buffer was incorrect size in 
                    DisplayATADriveIdentity routine.
                    Modified to CW Pro 1 and its headers
                    Added Metrowerks SIOUX specific stuff
                    Created Fat application
                    Realized that the words come back swapped; 
                    adjusted for this in the DumpFormatedBuffer routine.(BLoB)
    
 
*/
 
 
//------------------------------------------------------------------------------------
#pragma mark Includes
//------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <LowMem.h>
#include <Patches.h>
#include <Traps.h>
#include <Devices.h>
#include <ATA.h>
 
#ifdef __MWERKS__
    #include <SIOUX.h>
#endif
 
#include "ATA Demo.h"
 
 
//------------------------------------------------------------------------------------
#pragma mark Globals
//------------------------------------------------------------------------------------
 
UInt8   gATAMgrPBVers;  // used to hold current version of PB from ataMgrInquiry
 
 
FormatTable kIdentFormat[] = {
    {    0,  0, kHex,       "Configuration word"                        },
    {    1,  1, kDecimal,   "Cylinders"                                 },
    {    3,  3, kDecimal,   "Heads"                                     },
    {    4,  4, kDecimal,   "Bytes/Track"                               },
    {    5,  5, kDecimal,   "Bytes/Sector (0 = 512 bytes)"              },
    {    5,  5, kDecimal,   "Sectors/Track"                             },  /* 35 */
    {    7,  9, kHex,       "Vendor Unique (word 7..9)"                 },
    {   10, 19, kRightJust, "Serial Number"                             },
    {   20, 20, kHex,       "Buffer Type"                               },
    {   21, 21, kDecimal,   "Buffer size in 512 byte increments"        },
    {   22, 22, kDecimal,   "Number of ECC bytes available"             },
    {   23, 26, kLeftJust,  "Firmware Revision"                         },
    {   27, 46, kLeftJust,  "Model Number"                              },
    {   47, 53, kHex,       "Capability Flags (word 47..53)"            },
    {   54, 54, kDecimal,   "Cylinders (current mode)"                  },
    {   55, 55, kDecimal,   "Heads (current mode)"                      },
    {   56, 56, kDecimal,   "Sectors/Track (current mode)"              },
    {   57, 58, kDecimal,   "Current Capacity in Sectors"               },
    {   59, 59, kHex,       "Multiple Sector Capability Flag"           },
    {   60, 61, kDecimal,   "Current User-addressable Sectors"          },
    {   62, 62, kHex,       "Single Word DMA Transfer Mode Flags"       },
    {   63, 63, kHex,       "Multiword DMT Transfer Mode Flags"         },
    {    0,  0, kEndOfTable,""                                          }
};
 
//------------------------------------------------------------------------------------
#pragma mark -
//------------------------------------------------------------------------------------
 
 
// ---------------------------------------------------------------------------
void     main   (void)
// ---------------------------------------------------------------------------
{
    OSErr           status;
    SInt16          drvrRefNum  = 0;
    
#ifdef __MWERKS__
    SIOUXSettings.asktosaveonclose = false;
    SIOUXSettings.columns = 88;
#endif
 
    printf("Macintosh ATA Manager Sample\n\n");
 
// Check for ATA Hardware 
// you should do this before calling the ATAManager, since some early ROMS
// could indicate an ATA manager without the proper HW, thus casing a crash.
    if (ATAHardwarePresent() == false) {
        printf("ATA Hardware is not present on this system\n");
        exit(EXIT_FAILURE);
    }
 
// Check for ATA Manager
    if (ATAManagerPresent() == false) {
        printf("ATA Manager is not present on this system\n");
        exit(EXIT_FAILURE);
    }
        
// Display ATA Manager Info
    status = DisplayATAManagerInquiryInfo();
    if (status != noErr) {
        printf("Cannot access ATA Manager: %d\n", (int) status);
        exit(EXIT_FAILURE);
    }
 
// Disable the CD driver 
    status = OpenDriver("\p.AppleCD", &drvrRefNum); 
    if (status == noErr) {
        printf("Found .AppleCD driver, preparing to disable it\n");
        status = DisableCDDriver(drvrRefNum);
    }
    
// Display ATA Device Info
    status = ScanATABusses();
    if (status != noErr) {
        printf("Cannot access ATA Manager: %d\n", (int) status);
        exit(EXIT_FAILURE);
    }
    
// Renable the CD driver
    if(drvrRefNum != 0)
    {
        printf("Re-enabling the .AppleCD driver \n");
        status = EnableCDDriver(drvrRefNum);
    }
    
    
}
 
 
// ---------------------------------------------------------------------------
OSErr       DisplayATAManagerInquiryInfo (void)
// ---------------------------------------------------------------------------
//
//  Display information about the ATA Manager
//
{
    ataMgrInquiry   pb;
    OSErr           status;
 
    CLEAR(pb);
    
    pb.ataPBFunctionCode =  kATAMgrManagerInquiry;
    pb.ataPBVers =          kATAPBVers1;
 
    status = ataManager((ataPB*) &pb );
    IF_ERROR(status, "ATA Manager Inquiry failed\n")
 
    printf("ATA Manager inquiry:\n");
    PrintNumVersion("\tATA Manager Version:", pb.ataMgrVersion);
    printf("\tBusses:\t\t%d\n\tDevices:\t%d\n",
                pb.ataBusCnt, pb.ataDevCnt);
    printf("\tPIO Modes:\t%x\n\tDMA Modes:\t%d\n\tMulti DMA Modes:%x\n",
                 pb.ataPioModes, pb.ataSingleDMAModes, pb.ataMultiDMAModes);
    printf("-----------------------------------------\n\n");    
    
    gATAMgrPBVers = pb.ataMgrPBVers;    // remember current PB version
    
    return (status);
}
 
 
// ---------------------------------------------------------------------------
OSErr       ScanATABusses (void)
// ---------------------------------------------------------------------------
//
//  Display information about the ATA Busses
//
{
    ataDrvrRegister     pb;
    OSErr               status;
 
// Get first device ID (yes you have to do this once)
    CLEAR(pb);
    pb.ataPBFunctionCode    =   kATAMgrFindDriverRefnum;
    pb.ataPBVers            =   kATAPBVers1;
    pb.ataPBDeviceID        =   (UInt32)0x0000ffff;
    status                  =   ataManager((ataPB*) &pb );
 
// loop through devices
    for (pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID;
         pb.ataPBDeviceID != 0xff;
         pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID)
        {           
            status = ataManager((ataPB*) &pb );
            IF_ERROR(status, "ATA Find Driver failed\n")
            
            printf("\nDevice %d %#s\n", pb.ataPBDeviceID, DrvrRefToName(pb.ataDrvrRefNum) );
            DisplayATADriveIdentity(pb.ataPBDeviceID);
            
            
        printf("-----------------------------------------\n");  
        };  
    
    printf("\n");   
    return (status);
}
 
 
 
// ---------------------------------------------------------------------------
OSErr       DisplayATADriveIdentity (UInt32 deviceID)
// ---------------------------------------------------------------------------
//
//  Display information about the ATA Identify Info
//
{
    ataIdentify         pb;
    ataDevConfiguration pb1;
    UInt8       devType;
    UInt16      buffer[256];
    OSErr       status;
    UInt8       dataBuffer[4096];
    
    
 
// Get Driver Configuration
    CLEAR(pb1);
    pb1.ataPBFunctionCode   =   kATAMgrGetDrvConfiguration;
    pb1.ataPBVers           =   kATAPBVers2;
    pb1.ataPBDeviceID       =   deviceID;
    
    status = ataManager((ataPB*) &pb1 );
    IF_ERROR(status, "ATA GetDrvConfiguration failed\n")
 
 
// Setup Identify block;
    CLEAR(pb);
    pb.ataPBFunctionCode    =   kATAMgrDriveIdentify;
    pb.ataPBVers            =   kATAPBVers1;
    pb.ataPBDeviceID        =   deviceID;
    pb.ataPBFlags           =   mATAFlagIORead + mATAFlagByteSwap ;
    
    if(pb1.ataDeviceType == kDevATAPI) pb.ataPBFlags += mATAFlagProtocol1;
    
    pb.ataPBTimeOut         =   100;
    pb.ataPBBuffer          =   (void*) buffer;
    
    status = ataManager((ataPB*) &pb );
    IF_ERROR(status, "ATA DriveIdentify failed\n")
 
    printf("Configuration: (");
 
    switch(pb1.ataDeviceType){
        case kDevUnknown:   
                        printf("Unknown protocol");
                        devType = 0;
                        break;
        
        case kDevATA:
                        printf("ATA");
                        devType = kDevATA; 
                        break;
                             
        case kDevATAPI: 
                        printf("ATAPI"); 
                        devType = kDevATAPI; 
                        break;
                        
        case kDevPCMCIA:    
                        printf("PCMCIA"); 
                        devType = kDevATA; 
                        break;
    }
    
    switch(pb1.ataSocketType){
        case kSocketUnknown:    
                        printf(", Unknown Socket"); 
                        break;
        
        case kSocketInternal:
                        printf(", Internal"); 
                        break;
                             
        case kSocketMediaBay:   
                        printf(", Media Bay"); 
                        break;
                        
        case kkSocketPCMCIA:    
                        printf(", PCMCIA, Vcc=%d, Vpp1=%d, Vpp2=%d", 
                                        pb1.atapcVcc, pb1.atapcVpp1,pb1.atapcVpp2); 
                        break;
    }
 
    printf(")\n");
 
    DumpFormatedBuffer(buffer, kIdentFormat);
    
    // read and display sector 0
    if( (devType == kDevATA) )
    {
        status = ATARead( pb1.ataPBDeviceID, dataBuffer );
        
        if( status == noErr )
        {
            printf( "\n*********************************** Sector 0 ***********************************\n\n" );
            DumpRawBuffer( dataBuffer, 512 );
        }
        else
            printf( "\nATA read failed: %d\n", status );
    }
    else if( devType == kDevATAPI )
    {
        status = ATAPIRead( pb1.ataPBDeviceID, dataBuffer );
        
        if( status == noErr )   
        {
            printf( "\n*********************************** Sector 0 ***********************************\n\n" );
            DumpRawBuffer( dataBuffer, 2048 );
        }
        else
            printf( "\nATAPI read failed: %d\n", status );
    }
        
    return status;
}
 
 
 
// ---------------------------------------------------------------------------
OSErr       DisableCDDriver (SInt16 refNum)
// ---------------------------------------------------------------------------
//
// Disable the CD driver
//
{   OSErr status;
    printf("- Disable the CD Driver \n");
 
    // wake up drive
    status = WakeUpCDDrive (refNum);
    if (status != noErr)
    {
        return status;
    }
 
    // move driver to quiescent mode
    status = SetQuiescence (refNum, quiescenceON);
    if (status != noErr)
    {
        return status;
    }
 
    return noErr;
}
 
// ---------------------------------------------------------------------------
OSErr       EnableCDDriver (SInt16 refNum)
// ---------------------------------------------------------------------------
//
//  Re-enable the CD driver
//
{   OSErr status;
 
    printf("- Enable the CD Driver \n");
 
    // move driver to quiescent mode
    status = SetQuiescence (refNum, quiescenceOFF);
    if (status != noErr)
    {
        return status;
    }
 
    return noErr;
}
 
// ---------------------------------------------------------------------------
OSErr       WakeUpCDDrive (SInt16 refNum)
// ---------------------------------------------------------------------------
//
//  Re-enable the CD driver
//
{   CntrlParam  pb;
    OSErr       status;
 
    printf("-- Wake up the CD Driver \n");
 
    CLEAR(pb);
 
    pb.ioCRefNum = refNum;
    pb.csCode = csSetPowerMode;
    *(UInt8 *) &pb.csParam[0] = pmActive;
    
  // send command to the CD/DVD driver
    status = PBControlImmed ((ParmBlkPtr) &pb);
 
    return status;
}
 
// ---------------------------------------------------------------------------
OSErr       SetQuiescence (SInt16 refNum, UInt16 mode)
// ---------------------------------------------------------------------------
//
//  Re-enable the CD driver
//
{
    CntrlParam  pb;
    OSErr       status;
 
    printf("-- Set the CD Driver Quiescence mode to %s\n",  
        (mode ==quiescenceOFF)? "Off":"On");
 
    CLEAR(pb);
 
    pb.ioCRefNum = refNum;
    pb.csCode = csQuiescence;
    pb.csParam[0] = mode;
    
  // send command to the CD/DVD driver
    status = PBControlImmed ((ParmBlkPtr) &pb);
 
    return status;
}
 
 
// ---------------------------------------------------------------------------
Boolean     ATAManagerPresent   (void)
// ---------------------------------------------------------------------------
//
// returns true if this machine has the ata manager
//
{
        return (TrapAvailable(kATATrap));
}
 
// ---------------------------------------------------------------------------
Boolean     ATAHardwarePresent      (void)
// ---------------------------------------------------------------------------
//
// returns true if this machine has ata hardware
//
{
    UInt16  configFlags;
 
    // Hardware configuration flags
    configFlags = LMGetHWCfgFlags();
    
    return (configFlags & 0x0080);
}
 
//------------------------------------------------------------------------------------
#pragma mark -
 
#define NumToolboxTraps() (                             \
        (NGetTrapAddress(_InitGraf, ToolTrap)           \
                == NGetTrapAddress(0xAA6E, ToolTrap))   \
            ? 0x200 : 0x400                             \
    )
#define GetTrapType(theTrap) (                          \
        (((theTrap) & 0x800) != 0) ? ToolTrap : OSTrap  \
    )
 
// ---------------------------------------------------------------------------
Boolean     TrapAvailable       (short theTrap)
// ---------------------------------------------------------------------------
// (see Inside Mac VI 3-8)
{
        TrapType                trapType;
        
        trapType = GetTrapType(theTrap);
        if (trapType == ToolTrap) {
            theTrap &= 0x07FF;
            if (theTrap >= NumToolboxTraps())
                theTrap = _Unimplemented;
        }
        return (
            NGetTrapAddress(theTrap, trapType)
            != NGetTrapAddress(_Unimplemented, ToolTrap)
        );
}
 
// ---------------------------------------------------------------------------
void        PrintNumVersion     (char *label, NumVersion version )
// ---------------------------------------------------------------------------
//
//  Decode version number info
//
{
    char            *stage;
 
    switch (version.stage) {
    case developStage:  stage = "d";        break;
    case alphaStage:    stage = "a";        break;
    case betaStage:     stage = "b";        break;
    case finalStage:    stage = "";         break;
    default:            stage = "?";        break;
    
    }
    printf("%s %d.%d.%d",
        label,
        version.majorRev,
        (version.minorAndBugRev>>4), (version.minorAndBugRev & 0xf),
        stage);
    if(version.stage != finalStage) printf(".%d",version.nonRelRev);
    
    printf(" (hex %08lx)\n",    (* ((unsigned long *) &version)));
}
 
 
 
// ---------------------------------------------------------------------------
void        DumpFormatedBuffer  (void* p,  const FormatTablePtr format) 
// ---------------------------------------------------------------------------
//
// Dump formatted buffer
//
 
{   
    unsigned short          *idInfo = p;
         
    register char           *charField;
    register short          fieldLength;
    register short          i;
    register long           value;
    register FormatTablePtr formatPtr;
    
#define FORMAT  (*formatPtr)
 
    for (formatPtr = format; FORMAT.format != kEndOfTable; formatPtr++) {
            printf("%35s", FORMAT.label);
            switch (FORMAT.format) {
            // Decimal values come as two words with the words swapped.
            case kDecimal:
                value = 0;
                for (i = FORMAT.lastWord; i >= FORMAT.firstWord; i--) {
                    value <<= 16;
                    value += idInfo[i];
                }
                printf(" %lu", value);  // was %lu
                break;
                
            case kHex:
                for (i = FORMAT.lastWord; i >= FORMAT.firstWord; i--) {
                    value = idInfo[i];
                    printf(" 0x%04X", value);
                }
                break;
                
            case kLeftJust:
                charField = (char *) &idInfo[FORMAT.firstWord];
                fieldLength = (FORMAT.lastWord - FORMAT.firstWord + 1)
                            * sizeof (unsigned short);
                /*
                 * First scan for an unspecified field.
                 */
                for (i = 0; i <= fieldLength; i++) {
                    if (charField[i] != '\0')
                        goto gotLeftJustField;
                }
                printf(" <not specified>");
                break;
                
gotLeftJustField:
                for (i = fieldLength; i > 0; --i) {
                    if (charField[i - 1] != ' ')
                        break;
                }
                printf(" \"%.*s\"", (int) i, charField);
                break;
                
            case kRightJust:
                charField = (char *) &idInfo[FORMAT.firstWord];
                fieldLength = (FORMAT.lastWord - FORMAT.firstWord + 1)
                            * sizeof (unsigned short);
                /*
                 * First scan for an unspecified field.
                 */
                for (i = 0; i <= fieldLength; i++) {
                    if (charField[i] != '\0')
                        goto gotRightJustField;
                }
                printf(" <not specified>");
                break;
                
gotRightJustField:
                for (i = 0; i < fieldLength; i++) {
                    if (charField[i] != ' ')
                        break;
                }
                printf(" \"%.*s\"", (int) (fieldLength - i), &charField[i]);
                break;
                
            }
            printf("\n");
        }
//      DumpRawBuffer( p,512);
}   
    
// ---------------------------------------------------------------------------
void        DumpRawBuffer       ( UInt8 *bufferPtr, int length )
// ---------------------------------------------------------------------------
//
// Dump buffer
//
 
{
        register int            i;
        int                     lineStart;
        int                     lineLength;
        short                   c;
 
#define kLineSize   16
        for (lineStart = 0; lineStart < length; lineStart += lineLength) {
            lineLength = kLineSize;
            if (lineStart + lineLength > length)
                lineLength = length - lineStart;
            printf("%03x %3d:", lineStart, lineStart);
            for (i = 0; i < lineLength; i++)
                printf(" %02x", bufferPtr[lineStart + i] & 0xFF);
            for (; i < kLineSize; i++)
                printf("   ");
            printf("  ");
            for (i = 0; i < lineLength; i++) {
                c = bufferPtr[lineStart + i] & 0xFF;
                if (c > ' ' && c < '~')
                    printf("%c", c);
                else {
                    printf(".");
                }
            }
            printf("\n");
        }
}
 
 
        
// ---------------------------------------------------------------------------
char*       DrvrRefToName(short refNum)
// ---------------------------------------------------------------------------
//
//  lookup driver name in table
//
 
{
        AuxDCEHandle*       UTable  = (AuxDCEHandle*) LMGetUTableBase();
        DCtlPtr             dctl;
        Ptr                 p;  
        
        if(!refNum) return ((char*) "\p<none>");
 
        dctl = (DCtlPtr) *UTable[~refNum];
        p    =  dctl->dCtlDriver;
        if( dctl->dCtlFlags  & 0x0040) p = (void*) *p;
 
        return  ( p?(char*) (p+18):(char*)"\p-Purged-");
}