home *** CD-ROM | disk | FTP | other *** search
- /*
- File: StorageClassShim.c
-
- Contains: USB Storage Class Shim
-
- Version: 1.0
-
- Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
-
- */
-
- #include <Types.h>
- #include <Devices.h>
- #include <processes.h>
- #include <CodeFragments.h>
- #include <Resources.h>
- #include <DriverServices.h>
- #include <Folders.h>
- #include <USB.h>
-
- #include "StorageClassShim.h"
- #include "SampleStorageVersion.h"
- #include "SampleStorageDeviceID.h"
-
- // Enumerations for the range of Unittable entries
- // in which InstallDriverFromMemory will try to install the driver
- enum
- {
- kUnitTableEntryStart = 48,
- kUnitTableEntryEnd = 127
- };
-
- // These are the structures and definitions used for the Refnum Association array.
- // This array handles associating USBDeviceRefs with UnitTable Driver refnums, so
- // Drivers can be removed from the UnitTable when the drive is removed.
- enum
- {
- kMaxNumberOfDrives = 50
- };
-
- struct RefnumAssociation
- {
- USBDeviceRef theDevRef;
- DriverRefNum drvrRefNum;
- };
-
- typedef struct RefnumAssociation RefnumAssociation;
-
-
- // These are all variables that are global to the Shim
- static RefnumAssociation theRefAssoc[kMaxNumberOfDrives];
- static Boolean shimInFile;
- static FSSpec shimFSSpec;
- static TimerID gGiveTimeTimer = nil;
- static DriverRefNum gNewDrvrRef = 0;
-
- static OSStatus GiveTimeSecondaryInterrupt( void *p1, void *p2);
-
- unsigned char USBShim(void)
- {
- OSStatus status = noErr;
- USBDeviceNotificationParameterBlock pb;
-
- // Clear out the Association array
- BlockZero((Ptr) theRefAssoc, sizeof(RefnumAssociation) * kMaxNumberOfDrives);
-
- // Setup notification for Vendor Specific Devices
- pb.usbDeviceNotification = -1; // tell me about everything
- pb.usbClass = -1; // tell me about vendor specific
- pb.usbSubClass = -1;
- pb.usbProtocol = -1;
- pb.usbVendor = kDriverVendorID; // Only notify me for the shuttle cable
- pb.usbProduct = kDriverProductID; // allow any product ID to notify us
- pb.result = noErr;
- pb.callback = (USBDeviceNotificationCallbackProcPtr) &myNotificationCallback;
- pb.refcon = nil;
- USBInstallDeviceNotification (&pb);
-
- return 0;
- }
-
- static Boolean gControlCallIsDone = false;
-
- void ControlComplete( ParmBlkPtr paramBlock )
- {
- #pragma unused (paramBlock)
-
- gControlCallIsDone = true;
- }
-
- OSStatus ShimOpenDriver(USBDeviceRef theDevRef)
- {
- OSStatus theErr = noErr;
- Handle hDrvrResource;
- short loopCount;
- THz currentZone;
-
- // We have been notified of a new device, check to see if we already
- // have installed a driver the USB Device Ref.
- for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++)
- {
- if(theDevRef == theRefAssoc[loopCount].theDevRef)
- {
- // Driver has already been installed for this USBDeviceRef,
- // Nothing else needs to be done, report back noErr to the notifier
- return noErr;
- }
- }
-
- // No driver has been loaded for this USBDeviceRef, find the driver's 'ndrv' resource
- if (shimInFile)
- {
- short oldResFileID = 0,
- myResFileID = 0;
-
- SetResLoad(true);
- oldResFileID = CurResFile(); // get the current resource file ID
- myResFileID = FSpOpenResFile(&shimFSSpec, fsRdPerm);
- UseResFile(myResFileID); // point at the shim file
-
- currentZone = GetZone ();
- SetZone ( SystemZone() );
- hDrvrResource = GetResource('ndrv', 128); // read in the driver from a ndrv resource
- DetachResource(hDrvrResource); // Detach the resource so it hangs around in the system heap
- SetZone (currentZone);
-
- UseResFile(oldResFileID); // point at the original file
- CloseResFile(myResFileID); // Make sure the resource file is closed
- }
- else
- {
- hDrvrResource = GetResource('ndrv', 128); // read in the driver from a ndrv resource
- }
-
- // We have found the driver's 'ndrv' resource, install it into the UnitTable
- if (hDrvrResource)
- {
- long drvrSize;
- Ptr pDrvrInMemory;
- DriverRefNum drvrRefNum;
- void *pTheStorageClassDispatchTable;
- CFragSymbolClass symClass;
- CFragConnectionID connID;
- short loopCount;
-
- // Lock the Driver Resource in memory
- HLock(hDrvrResource);
-
- // Get the resource information needed to install the Driver
- pDrvrInMemory = *hDrvrResource;
- drvrSize = GetHandleSize(hDrvrResource);
-
- // Install the driver
- theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, (RegEntryIDPtr) nil, kUnitTableEntryStart, kUnitTableEntryEnd, &drvrRefNum);
- if ( theErr != noErr )
- {
- // The driver could not be loaded, the shim will return the error and abort the driver load
- return theErr;
- }
-
- gNewDrvrRef = drvrRefNum;
-
- // Save the Driver refnum to remove the driver when the remove notification is recieved
- for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++ )
- {
- if (( theRefAssoc[loopCount].theDevRef == 0 ) && (theRefAssoc[loopCount].drvrRefNum == 0) )
- {
- theRefAssoc[loopCount].theDevRef = theDevRef;
- theRefAssoc[loopCount].drvrRefNum = drvrRefNum;
- break;
- }
- }
-
- // If the array is already full, this drive will not be added to the array. This means that the Shim will never
- // remove the driver it the drive is detached. This will only happen if more than kMaxNumberOfDrives are attached
- // at any one time.
-
- // Get the Storage class dispatch table
- USBGetDriverConnectionID(&theDevRef, &connID);
- currentZone = GetZone ();
- SetZone ( SystemZone() );
-
- theErr = FindSymbol(connID, "\pTheStorageClassDispatchTable", (Ptr *)&pTheStorageClassDispatchTable, &symClass);
- SetZone (currentZone);
-
- // If no error occured, pass the dispatch table pointer to the Driver
- if (theErr == noErr)
- {
- CntrlParam cntrlPB;
-
- cntrlPB.ioCompletion = NewIOCompletionProc( &ControlComplete );
- cntrlPB.ioVRefNum = 0;
- cntrlPB.ioCRefNum = drvrRefNum;
- cntrlPB.csCode = 500; // currently the code for set dispatch table;
- *((UInt32 *) &cntrlPB.csParam[0]) = (UInt32) pTheStorageClassDispatchTable;
-
- gControlCallIsDone = false;
-
- theErr = PBControlAsync((ParmBlkPtr) &cntrlPB );
- if(theErr == noErr)
- {
-
- // Wait for the control call to complete
- // Loop doing nothing until call is done
- while (gControlCallIsDone == false);
- }
- }
-
- if ( theErr != noErr )
- {
- // if an error occurs, we should remove the driver from the unittable
- }
- }
-
- return theErr;
- }
-
- OSStatus ShimCloseDriver(USBDeviceRef theDevRef)
- {
- OSStatus theErr = noErr;
- short loopCount;
-
- for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++)
- {
- if(theDevRef == theRefAssoc[loopCount].theDevRef)
- {
- if(theRefAssoc[loopCount].drvrRefNum != 0)
- {
- VCBPtr vol;
-
- vol = (VCBPtr) (GetVCBQHdr())->qHead;
-
- while (vol)
- {
- // Check to see if this volume belongs to the driver
- // that is being removed
- if( vol->vcbDRefNum == theRefAssoc[loopCount].drvrRefNum)
- {
- IOParam offlinePB;
- OSErr err;
-
- BlockZero(&offlinePB, sizeof(IOParam));
- offlinePB.ioCompletion = nil;
- offlinePB.ioResult = noErr;
- offlinePB.ioNamePtr = nil;
- offlinePB.ioVRefNum = vol->vcbVRefNum;
-
- //err = PBOffLine((ParamBlockRec *) &offlinePB);
- err = PBUnmountVol((ParamBlockRec *) &offlinePB);
- if(err == fBsyErr)
- {
- err = PBEject((ParamBlockRec *) &offlinePB);
- gNewDrvrRef = 0;
- }
- }
-
- vol = (VCBPtr) vol->qLink;
- }
-
- theErr = RemoveDriver(theRefAssoc[loopCount].drvrRefNum, false);
- theRefAssoc[loopCount].theDevRef = 0;
- theRefAssoc[loopCount].drvrRefNum = 0;
-
- if(gNewDrvrRef == 0)
- {
- OSStatus status;
- AbsoluteTime theWait;
-
- theWait = DurationToAbsolute(durationSecond);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- status = SetInterruptTimer( &theWait, &GiveTimeSecondaryInterrupt, nil, &gGiveTimeTimer);
- }
- }
-
- return theErr;
- }
- }
-
- return theErr;
- }
-
- OSStatus GiveTimeSecondaryInterrupt( void *p1, void *p2)
- {
- #pragma unused ( p1, p2 )
- Boolean DrvrVolumeFound = false;
-
- gGiveTimeTimer = nil;
-
- if(gNewDrvrRef != 0)
- {
- VCBPtr vol;
-
- vol = (VCBPtr) (GetVCBQHdr())->qHead;
-
- while (vol)
- {
- // Check to see if this volume belongs to the driver
- // that is being removed
- if( vol->vcbDRefNum == gNewDrvrRef)
- {
- DrvrVolumeFound = true;
- break;
- }
-
- vol = (VCBPtr) vol->qLink;
- }
- }
-
- if( DrvrVolumeFound == false )
- {
- OSStatus status;
- AbsoluteTime theWait;
-
- SystemTask();
- theWait = DurationToAbsolute(durationSecond);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- status = SetInterruptTimer( &theWait, &GiveTimeSecondaryInterrupt, nil, &gGiveTimeTimer);
- }
-
- return noErr;
- }
-
- void myNotificationCallback(USBDeviceNotificationParameterBlock *pb)
- {
- switch(pb->usbDeviceNotification) // why were we notified?
- {
- case kNotifyAddDevice: // because mass storage device appeared
- case kNotifyAddInterface: // because mass storage interface appeared
- {
- ShimOpenDriver(pb->usbDeviceRef);
- }
- break;
-
- case kNotifyRemoveDevice: // because a mass storage device or interface disappeared
- case kNotifyRemoveInterface: // because a mass storage device or interface disappeared
- {
- ShimCloseDriver(pb->usbDeviceRef);
- }
- break;
-
- default:
- break;
- }
- }
-
- void USBShimTermination(void)
- {
- // put back the original vectors
- }
-
- OSErr CFragInitRoutine(CFragInitBlockPtr initBlkPtr)
- {
- shimInFile = false;
-
- if (CFragHasFileLocation(initBlkPtr->fragLocator.where))
- {
- shimInFile = true;
- shimFSSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec); // save the FSSpec, in case we need it later
- }
- return noErr;
- }
-