Load PCI Driver.c

/*
    File:       Load PCI Driver.c
 
    Contains:   Load PCI Driver Sample,This Code loads Wayne Flansburg PCI 'ndrv'
                so you can see it load without having to have a PCI card installed.
                This requires the PCI interfaces and libraries from ETO.
 
    Written by: Matthew Xavier Mora 
 
    Copyright:  Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/3/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                06/11/97    mxm             Fixed the error -2538 by passing nil for the regID.
                04/15/97    mxm             Cleaned it up for the Dev CD
                03/28/97    mxm             Took out the MyFindSpaceInUnitTable routine. I wasn't using the 
                                            InstallDriverFromFile correctly. HighestUnitNumber wasn't the problem.
                                            That's what I get for trying to program without the Documentation.
                                            Added Drag Manger and ODoOC support so you can drag a driver
                                            into the window or on the application and it will load it.
                                            Display more info from the driver.
                03/25/97    mxm             Moved to a real app
                                            Fixed the can't load the library a second time bug.
                                            I was using HighestUnitNumber to get the unit number to load.
                                            I thought this call found the last used unit number. It
                                            actually expanded the unit table to the max number of 
                                            entries! I put in MyFindSpaceInUnitTable routine and use it instead.
                                            Fix crashing Malph by moving it into an application shell. I don't 
                                            know why it would cause Malph to crash.
 
    
                
                02/01/96    mxm             I wrote the first version in the "Writing PCI drivers" class. Got it to load
                                            the sample driver I was writing. No real user interface
                                            to speak of.
                                            
*/
//------------------------------------------------------------------
#pragma mark Includes
//------------------------------------------------------------------
 
#include <Devices.h>
#include <NameRegistry.h>
#include <StandardFile.h>
#include <LowMem.h>
#include <Dialogs.h>
#include "SimpleApp.h"
#include <stdio.h>
#include <string.h>
#include <TextUtils.h>
#include <CodeFragments.h>
 
//------------------------------------------------------------------
#pragma mark Prototypes
//------------------------------------------------------------------
 
pascal  OSErr   FSpGetFullPath(const FSSpec *spec, short *fullPathLength, Handle *fullPath);
 
//------------------------------------------------------------------
#pragma mark Globals
//------------------------------------------------------------------
 
short   gDrvrRefNum = 0; /* global variable for storing my driver reference number */
long    gLoadButton;
long    gUnloadButton;
short   gVert;
short   gLineHeight;
NMRec   gAlertNMRec;
Str255  gAlertStr = "\pAn error occurred. Please bring Matt's PCI Loader to the front.";
short   gError = 0;
 
//------------------------------------------------------------------
#pragma mark Defines
//------------------------------------------------------------------
 
#pragma mark -
 
//------------------------------------------------------------------
static void AlertUser(short err)
//------------------------------------------------------------------
{
    // in this case just set the global and the idle routine will display the error
    gError = err;
}
 
/*
// I grabbed this code from somewhere
//------------------------------------------------------------------
static short MyFindSpaceInUnitTable(void)
//------------------------------------------------------------------
{
    Ptr         curUTableBase, newUTableBase;
    short           curUTableEntries, newUTableEntries;
    short           refNum, unitNum;
    
    // get current unit table values from low memory globals 
    curUTableEntries = LMGetUnitTableEntryCount();
    curUTableBase   = LMGetUTableBase();
    
    // search for empty space in the current unit table 
    for ( unitNum = curUTableEntries - 1; 
            unitNum >= 48; // lowest available unit number 
            unitNum-- )
    {
        refNum = ~(unitNum);
        if (GetDCtlEntry(refNum) == nil)
            return(unitNum); // found a space 
    }
    
    
    // no space in the current table, so make a new one 
    
    // increase the size of the table by 16 (an arbitrary value)
    newUTableEntries = curUTableEntries + 16;
    
    // allocate space for the new table 
    newUTableBase =  NewPtrSysClear((long)newUTableEntries * sizeof(Handle));
    if (newUTableBase == nil) {
        return(MemError());
    }
    // copy the old table to the new table 
    BlockMoveData(curUTableBase, newUTableBase, (long)curUTableEntries * sizeof(Handle));
    
    // set the new unit table values in low memory 
    LMSetUTableBase(newUTableBase);
    LMSetUnitTableEntryCount( newUTableEntries);
    
    unitNum = newUTableEntries - 1;
 
    // unitNum = 0; //uh bad thing man.
    return(unitNum); 
}
 
*/
 
 
//------------------------------------------------------------------
static void ForceUpdate(void)
//------------------------------------------------------------------
{
    if (gSACurrentWindow) {
        SetPort(gSACurrentWindow);
        InvalRect(&gSACurrentWindow->portRect);
    }   
}
 
//------------------------------------------------------------------
static void UnloadDriver(void)
//------------------------------------------------------------------
{
    short err;
    
    if (gDrvrRefNum) { 
        err = RemoveDriver(gDrvrRefNum, true);
        gDrvrRefNum = 0;
    }
}
 
//------------------------------------------------------------------
static short InstallDriver(FSSpecPtr spec) 
//------------------------------------------------------------------
{
    RegEntryID          device={0,0};
    short               lowUnitNumber,hiUnitNumber ;    
    short               err = -1;   
        
    
    if (gDrvrRefNum) {
        UnloadDriver();
    }
     lowUnitNumber = 48 ; // MyFindSpaceInUnitTable();
     hiUnitNumber = HighestUnitNumber();
     
    if (lowUnitNumber > 0) {
    
        err = InstallDriverFromFile(spec,nil,lowUnitNumber ,hiUnitNumber,&gDrvrRefNum);
        if (err != noErr) {
            AlertUser(err);  // we can be called from inside a drag handler so just set a flag
            SAEnableObject(gLoadButton);
            SADisableObject(gUnloadButton);
        } else {
            SAEnableObject(gUnloadButton);
            SADisableObject(gLoadButton);
        }
    } 
    ForceUpdate();
    return err; 
}
 
// Load a driver via StandardFile
//------------------------------------------------------------------
static  short LoadDriver(void)
//------------------------------------------------------------------
{
 
    short               err = -1;
 
    OSType              typeList[4];
    OSType *            typeListPtr = typeList;
    StandardFileReply   reply;
 
    
    typeList[0] = 'ndrv';
        
    StandardGetFile(nil,1,typeList,&reply);
    if (reply.sfGood) {
        err = InstallDriver(&reply.sfFile);
    }
    
    return err; 
}
 
// ODOC handler
//------------------------------------------------------------------
static pascal OSErr     MyOpenFileProc(FSSpecPtr myFSSPtr)
//------------------------------------------------------------------
{
    short err;
    
    err =  InstallDriver(myFSSPtr) ;
    return noErr;
}
 
 
//------------------------------------------------------------------
static  pascal short DoIdle(EventRecord *evt)
//------------------------------------------------------------------
{
        Str255 tempStr; 
        short err;
#pragma unused (evt)
    // in case we want to do something at idle time
    
    if (gError) {
        gAlertNMRec.qType       = nmType;
        gAlertNMRec.nmFlags     = 0;
        gAlertNMRec.nmPrivate   = 0;
        gAlertNMRec.nmReserved  = 0;
        gAlertNMRec.nmResp      = nil;
        gAlertNMRec.nmStr       = gAlertStr;
        gAlertNMRec.nmSound     = nil;
        gAlertNMRec.nmMark      = 1;
        gAlertNMRec.nmIcon      = nil;
        err = AEInteractWithUser(kAEDefaultTimeout,&gAlertNMRec,nil);   
        
        NumToString(gError,tempStr);
        ParamText(tempStr,"\p","\p","\p");
        Alert(1002,nil);
        gError = 0;
    }
    return noErr;
}
 
//------------------------------------------------------------------
    static  pascal short DoLoadDriver(ButtonItemRef me,long refCon)
//------------------------------------------------------------------
{
#pragma unused (me,refCon)
    short err;
    
    err = LoadDriver();
    if (err == noErr ) {
        SADisableMe();
        SAEnableObject(gUnloadButton);
        ForceUpdate();
    }
    return noErr;
}
 
//------------------------------------------------------------------
    static  pascal short DoUnloadDriver(ButtonItemRef me,long refCon)
//------------------------------------------------------------------
{
#pragma unused (me,refCon)
 
    UnloadDriver();
    SADisableMe();
    SAEnableObject(gLoadButton);
    ForceUpdate();
    
    return noErr;
}
 
//------------------------------------------------------------------
    static GetLineHeight(void)
//------------------------------------------------------------------
{
    FontInfo info;
    
    GetFontInfo(&info);
    return (info.ascent + info.descent + info.leading);
}
 
//------------------------------------------------------------------
    static void DrawItem(StringPtr label,StringPtr text)
//------------------------------------------------------------------
{
        DrawString (label);
        DrawString (text);
        MoveTo(5,gVert);
        gVert += gLineHeight; 
}
 
//------------------------------------------------------------------
    static void DrawHex(StringPtr label,long n)
//------------------------------------------------------------------
{
        char s[256];
        
        sprintf(s,"%0X",n);
        DrawString (label);
        DrawText(s,0,strlen(s));
        MoveTo(5,gVert);
        gVert += gLineHeight; 
}
 
//------------------------------------------------------------------
    static void DrawHandle(StringPtr label,Handle text)
//------------------------------------------------------------------
{
    DrawString (label);
    if (text) {
        DrawText (*text,0,GetHandleSize(text));
    }
    MoveTo(5,gVert);
    gVert += gLineHeight; 
}
 
//------------------------------------------------------------------
    static void DrawNumber(StringPtr label,long n)
//------------------------------------------------------------------
{   
    Str255 tempStr;
 
    NumToString(n,tempStr);
    DrawString (label);
    DrawString (tempStr);
    MoveTo(5,gVert);
    gVert += gLineHeight; 
}
 
//------------------------------------------------------------------
    static  pascal short MyUpdate(long refCon)
//------------------------------------------------------------------
{
#pragma unused (refCon)
    Str255              tempStr;
    UnitNumber          unitNum;
    DriverFlags         flags;
    DriverOpenCount     count;
    RegEntryID          device;
    CFragSystem7Locator driverLoadLocation;
    CFragConnectionID   fragmentConnID;
    DriverEntryPointPtr fragmentMain;
    DriverDescription   driverDesc;
    FSSpec              fileSpec;
    Handle              fullPath = nil;
    short               err = 0;
    short               fullPathLength;
    
    gLineHeight = GetLineHeight();
    
    gVert = 120;
    MoveTo(5,gVert);
    gVert += gLineHeight; 
    
    if (gDrvrRefNum) {
    
        DrawString("\pThe driver is loaded. refNum = (");
        NumToString(gDrvrRefNum,tempStr);
        DrawString (tempStr);
        DrawString("\p)");
        MoveTo(5,gVert);
        
        gVert += gLineHeight; 
        driverLoadLocation.u.onDisk.fileSpec = &fileSpec;
        err =  GetDriverInformation(gDrvrRefNum,
                                    &unitNum, 
                                    &flags, 
                                    &count,
                                    tempStr, 
                                    &device,
                                    &driverLoadLocation,
                                    &fragmentConnID,
                                    &fragmentMain, 
                                    &driverDesc);
        
        DrawItem("\pName: ",tempStr);
        DrawNumber("\pUnitNumber: ",unitNum);   
        DrawNumber("\pCount: ",count);
        DrawHex("\pflags: ",flags);
 
        err = FSpGetFullPath(&fileSpec,&fullPathLength, &fullPath);
        if (fullPath) {
            DrawHandle("\pPath: ",fullPath);
            DisposeHandle(fullPath);
        }   
        DrawHex("\pFragment Main: 0x",(long)fragmentMain);      
    } else {
        DrawString("\pNo Driver Loaded.             ");
    }
    
    return noErr;
}
 
//---------------------------------------------------------------------------------------
    static pascal OSErr MyPutData (ObjectItemRef orh,OSType kind,Ptr  data,long len,long flags)
//---------------------------------------------------------------------------------------
{
#pragma unused (orh,len,flags)
 
    HFSFlavor * theFile;
    
    if (kind == flavorTypeHFS) { 
        theFile = (HFSFlavor *)data;
        
        if (theFile->fileType == 'cfrg' ) {
            InstallDriver(&theFile->fileSpec);
        }
    }
 
 
    return noErr;
}
 
 
// The drag receive handler
//------------------------------------------------------------------
static pascal short MyReceive(ObjectItemRef orh,DragReference theDrag)
//------------------------------------------------------------------
{
#pragma unused(orh)
    ItemReference   itemRef;
    Size            dataSize;
    HFSFlavor       theHFSFlavor;
    OSErr           retCode;
 
 
    // There is only one item, so get its reference number.
    retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef);
    
    if (retCode == noErr) {
        dataSize = sizeof(HFSFlavor);
        retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &theHFSFlavor, &dataSize, 0);
        if (retCode == noErr)  {
            InstallDriver(&theHFSFlavor.fileSpec) ;
        }
 
    }
    return retCode;
}
 
//------------------------------------------------------------------
void main(void)
//------------------------------------------------------------------
{ 
    long    buttonID    = 1;
    long    textID      = 2;
    long    dragID      = 3;
    Str255  tempStr;
    Rect    r ;
    long    gMyWindowID;
    short   err;
    
    InitSimpleApp(2,kUseStandardMenu);      // Simple App Sets up the Tool Box For us 
    gMyWindowID = GetDocumentWindow (128);  // Get our stored window 
    SetOpenFileProc (MyOpenFileProc);       // set open file proc. This is called on an ODOC event
    
    SetWTitle(gSACurrentWindow,"\pMatt's PCI Driver Loader");
    
    InstallIdleProc(DoIdle);
    SetWindowUpdateProc(gSACurrentWindow,MyUpdate );    //gSACurrentWindow for now, its a Kludge
    GetIndString(tempStr,kStaticStrings,kButtonName);   // Get button name
 
    SetRectDimensions(&r, 180, 20);         // This Sets its size without changing it position
    SetRectLocation(&r, 10, 30);            // This Sets a rects anchor point
    (void)InstallPushButton(&buttonID,gSACurrentWindow,tempStr,&r,0,DoLoadDriver,nil);
    gLoadButton = buttonID;
    OffsetRect(&r,200,0);
    GetIndString(tempStr,kStaticStrings,3); // Get button name
    (void)InstallPushButton(&buttonID,gSACurrentWindow,tempStr,&r,0,DoUnloadDriver,nil);
    gUnloadButton = buttonID;
    SADisableMe();
    
    
    SetRect(&r,4,55,gSACurrentWindow->portRect.right - 4,110);      
    GetIndString(tempStr,kStaticStrings,kAboutText);    // Get about this snippet text
    (void)InstallStaticText(&textID,gSACurrentWindow,tempStr,&r);   
    
    // lets add drag and drop support for our window    
    err = InstallDragObject(&dragID,gSACurrentWindow,"\p",&gSACurrentWindow->portRect, nil, nil, MyReceive, 0);
    err = SAInstallStandardDragHandlers(gSACurrentWindow);              // enable dragging
    err = SAAddWindowDragDataTypes(gSACurrentWindow,flavorTypeHFS);     // we accept flavorTypeHFS
 
    Run();                                                              //Let SimpleApp handle the rest
        
    // lets check and see if the driver is still loaded and ask the 
    // user what to do if it is loaded
    if (gDrvrRefNum) {
        short itemHit;
 
        itemHit = Alert(1001,nil);
        if (itemHit == 1 ) {
            UnloadDriver();
        }
    }
}