home *** CD-ROM | disk | FTP | other *** search
- /*
- File: StorageClassUTFunctions.c
-
- Contains: All device specific functions
-
- Version: 1.1
-
- Copyright: © 1998-1999 by Apple Computer, Inc., all rights reserved.
-
- File Ownership:
-
- DRI: Craig Keithley
-
- Other Contact: xxx put other contact here xxx
-
- Technology: USB Drivers
-
- Writers:
-
- (TM) Tim McLeod
- (CJK) Craig Keithley
-
- Change History (most recent first):
-
- <USB3> 2/16/99 TM Removed internal parameter block initialization from
- DriverStatusCmd routine and added a check for specific control
- calls before initializing the parameter block in the
- DriverControlCmd routine.
- <USB2> 1/11/99 CJK update to use sources from 1.1f3 DDK
-
- */
-
- #include <Disks.h>
- #include <DriverGestalt.h>
- #include <Gestalt.h>
- #include <NameRegistry.h>
- #include <Power.h>
- #include <Resources.h>
- #include <Strings.h>
-
- #include "SampleStorageDriverAPI.h"
- #include "SampleStorageVersion.h"
- #include "StorageClassUTFunctions.h"
- #include "StorageClassUTDriver.h"
- #include "StorageClassUTDriverIcons.h"
-
- enum
- {
- kReadWriteRetryCount = 1,
- kFormatRequestSenseRetryCount = 5
- };
-
- enum {
- // kCDBSize = 12,
- kSenseDataSize = 18
- };
-
-
- enum {
- kCmdFormat = 0x04,
- kCmdInquiry = 0x12,
- kCmdModeSelect = 0x55,
- kCmdModeSense = 0x5A,
- kCmdPreventAllowRemoval = 0x1E,
- kCmdRead = 0x28,
- kCmdReadCapacity = 0x25,
- kCmdReadFormatCapacities = 0x23,
- kCmdRequestSense = 0x03,
- kCmdRezero = 0x01,
- kCmdSeek = 0x2B,
- kCmdSendDiagnostic = 0x1D,
- kCmdStartStopUnit = 0x1B,
- kCmdTestUnitReady = 0x00,
- kCmdWrite = 0x2A,
- kCmdWriteVerify = 0x2E,
- kCmdVerify = 0x2F
- };
-
- // The structure for getting the media capacity from the device
- struct ReadCapacityData
- {
- UInt32 lastLogicalBlock; // Last valid LBA
- UInt32 blockLength; // Block length in bytes
- };
- typedef struct ReadCapacityData ReadCapacityData, *ReadCapacityDataPtr;
-
- // This structure defines each volume (partition) on a physical drive (media)
- struct VolumeRec // This is needed to support multiple partitions
- {
- DrvSts2 driveStatus; // drive status info & queue element
- UInt16 vRefNum; // drive number for this volume
- Boolean mountthispart; // mount this volume indicator
- Boolean partmounted; // volume mounted indicator
- UInt32 partitionNo; // the partition number for the volume
- UInt32 partoffset; // phys. offset of data partition
- UInt32 curoffset; // 0 = physical mapping, else 'partoffset'
- UInt32 partblks; // number of blocks in the partition
- Ptr nextVol; // Link to next volume in the list
- Ptr drivePtr; // Pointer to the owning drive's record
- Ptr mediaIconPtr; // Pointer to the media icon for this volume
- };
- typedef struct VolumeRec VolumeRec, *VolumeRecPtr;
-
- // This structure defines each physical drive…
- struct DriveRec
- {
- UInt32 capacity; // Drive capacity in blocks
- UInt32 blockSize;
- UInt16 numVolumes; // Number of partitions in the drive
- VolumeRecPtr nextVol; // Pointer to drive's volume list
- };
- typedef struct DriveRec DriveRec, *DriveRecPtr;
-
- // Our Sleep Queue structure. The driver installs a sleep queue proc to find
- // out when the machine goes into sleep or doze mode. When a sleep or doze
- // notification is received, the driver will stop polling for media until a wake
- // notification is received.
- struct OurSleepQRec
- {
- SleepQRec theSleepQRec;
- Boolean isInSleep;
- };
- typedef struct OurSleepQRec OurSleepQRec, *OurSleepQRecPtr;
-
- // The Drive Request PB structure contains all information need to perform
- // a device request
- struct DriveRequestPB
- {
- StorageExecuteCommandPB executePB;
- ParmBlkPtr theIOPB;
- IOCommandID ioCommandID;
- IOCommandKind ioCommandKind;
- volatile OSStatus status;
- UInt16 retryCount;
- Boolean doWrite;
- };
- typedef struct DriveRequestPB DriveRequestPB, *DriveRequestPBPtr;
-
- // The driver's global data structure
- struct UTDriverGlobals
- {
- DriveRequestPB drivePB;
-
- // Global Control/Status fields for the driver
- Boolean isFloppy;
- Boolean isWriteProtected;
- Boolean doInternalReadWrite;
- Boolean diskInDrive;
- UInt8 currentExecutionState;
-
- SInt16 drvrRefNum; // Our driver reference number
- ReadCapacityData getCapacity;
- UInt8 sense[40];
- DriveRec theDrive;
- VolumeRec theVolume;
- OurSleepQRec theSleepQRec;
- Str32 DriveInfoString;
- };
- typedef struct UTDriverGlobals UTDriverGlobals;
-
- // The values for the states of the state machines
- enum
- {
- // Mount State Machine
- kMountStartState = 1,
- kMountTURDoneState,
- kMountRequestSenseDoneState,
- kMountGetGeometryDoneState,
- kMountCheckGetGeometryErrorDone,
- kMountReadPossibleCapacitiesDone,
- kMountCheckWriteProtectDoneState,
- kMountPreventRemovalDoneState,
-
- // Eject State Machine
- kEjectStartState,
- kEjectAllowRemovalDone,
- kEjectCartridgeDone,
-
- // Format State Machine
- kFormatStartState,
- kFormatDoneState,
- kFormatWaitDoneState,
- kFormatRequestSenseDoneState,
- kFormatGetGeometryDoneState,
- kFormatCheckWriteProtectDoneState,
- kFormatPreventRemovalDoneState
- };
-
- /* Driver Control/Status Codes for Startup Disk Control Panel */
- enum
- {
- kcsSetBootPartitionCode = 44, // Set startup partition Control Call
- kcsGetBootPartitionStatus = 44 // Get startup partition Status Call
- };
-
- // Prototypes for the Sleep Queue related functions
- static void InstallInSleepQueue(OurSleepQRecPtr ourSleepQRec);
- static void RemoveFromSleepQueue(OurSleepQRecPtr ourSleepQRec);
- static long SleepNotification(long message, SleepQRecPtr sleepRec);
-
- // Prototypes for the cartridge mounting related functions
- static OSStatus MountSecondaryInterrupt( void *p1, void *p2);
- static void MountTheCartridge( void *theCurrentPB );
-
- // Prototypes for the cartridge ejecting related functions
- static void EjectTheCartridge( void *theCurrentPB );
-
- // Prototypes for the floppy formatting related functions
- static OSStatus FormatCompletionInterrupt( void *p1, void *p2);
- static void FormatTheCartridge( void *theCurrentPB );
-
- // ATAPI/SCSI-2 Device Commands
- static OSStatus CheckWriteProtect(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus TUR(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus GetMediaGeometry(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus ReadFormatCapacity(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus RequestSense(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus FormatFloppyCartridge(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus EjectCartridge(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion);
- static OSStatus PreventAllowRemoval(UTDriverGlobals *theCurrentPB, Boolean preventRemoval, StorageClassCompletionProcPtr ourCompletion);
-
- // Prototypes for the Read/Write functions and completion routines
- static OSStatus DoReadWriteCommand( UTDriverGlobals *theDriverPB, Boolean doWrite);
- static OSStatus ReadWriteBlock( UTDriverGlobals *theDriverPB, UInt32 startBlock, UInt32 numBlocks, Ptr buffer, Boolean doWrite, Boolean doAsync);
- static void ReadWriteCompletion( void *theDriverPB );
- static void WriteRequestSenseCompletion( void *theDriverPB );
- static void RequestSenseOnErrorCompletion( void *theDriverPB );
-
- // Prototypes for the Drive Queue and Volume Queue related functions
- static void InstallVolumes(DriveRecPtr theDrive, Boolean mountVols);
- static void RemoveVolume(DriveRecPtr drvRec, UInt16 volRef);
- static VolumeRecPtr GetVolume(DriveRecPtr drive, UInt16 vRefNum, UInt32 partitionNum);
- static VCB* MountedVolOfDrive(DriveRecPtr drive);
- static SInt16 NextQDrive();
- static VolumeRecPtr CreateVolume(DriveRecPtr drive, UInt32 partitionID, UInt32 volSize, UInt32 volOffset);
- static void RemoveDrive(DriveRecPtr theDrivePtr);
- static void UpdateQ(SInt16 qDrive, SInt32 newSize);
- static SInt32 NextPartitionID(DriveRecPtr drive);
- static Boolean InstallDrive(DriveRecPtr drive, Boolean mountVols);
- static OSErr MountVolumes( DriveRecPtr drive );
-
- // This is to workaround a bug in the PowerPC native version of the AddDrive
- // call in systems before 8.5, where one needs to be added to the desired
- // drive number before calling AddDrive.
- // This function will check the system and pass the appropriate value to AddDrive
- static void NativeAddDrive(SInt16 drvrRefNum, UInt16 driveNumber, DrvQElPtr drvQEl);
-
- //----------------------------------------------------------------------------------
- // Globals
- //----------------------------------------------------------------------------------
-
- static DriverLocationIcon gDriveIcon; // static structure for control calls
- static StorageClassDispatchTablePtr gItsTheDispatchTable = nil; // The class's dispatch table
- static TimerID gInterruptTimer = 0;
- static UTDriverGlobals gTheUTGlobals;
-
-
- //----------------------------------------------------------------------------------
- // Driver calls
- //----------------------------------------------------------------------------------
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverInitializeCmd ( AddressSpaceID addressSpaceID,
- DriverInitInfoPtr initialInfo)
- {
- #pragma unused (addressSpaceID, initialInfo)
-
- OSStatus err = noErr;
-
- IfDebugging("\pInitialize Driver");
- gTheUTGlobals.drvrRefNum = initialInfo->refNum;
- gTheUTGlobals.drivePB.theIOPB = nil;
- gTheUTGlobals.currentExecutionState = kMountStartState;
- gTheUTGlobals.doInternalReadWrite = false;
- gTheUTGlobals.diskInDrive = false;
-
- gTheUTGlobals.isFloppy = false;
-
- // Set up our color icon family
- BuildMediaIconFamily();
-
- // Clear out the Drive Record
- BlockZero((Ptr) &gTheUTGlobals.theDrive, sizeof(DriveRec));
-
- // Clear out the Volume Record
- BlockZero((Ptr) &gTheUTGlobals.theVolume, sizeof(VolumeRec));
-
- // Build the Drive Info string returned in Status/Control calls
- {
- Str32 tempStr;
-
- PStrCopy( gTheUTGlobals.DriveInfoString, "\pUSB (v");
- CStrToPStr(tempStr, kStorageStringVersShort); // driver version
- PStrCat(gTheUTGlobals.DriveInfoString, tempStr); // driver version
- PStrCat(gTheUTGlobals.DriveInfoString, "\p)");
- }
-
- BlockZero((Ptr) &gTheUTGlobals.theSleepQRec, sizeof(OurSleepQRec));
- InstallInSleepQueue( &gTheUTGlobals.theSleepQRec );
- return (err);
- }
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverFinalizeCmd (DriverFinalInfoPtr finalInfo)
- {
- #pragma unused (finalInfo)
- OSStatus err = noErr;
-
- DestroyMediaIconFamily();
- RemoveFromSleepQueue( &gTheUTGlobals.theSleepQRec );
-
- return (err);
- }
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverSupersededCmd (DriverSupersededInfoPtr supersededInfo)
- {
- #pragma unused (supersededInfo)
-
- OSErr err = noErr;
-
- return (err);
- }
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverReplaceCmd ( AddressSpaceID addressSpaceID,
- DriverReplaceInfoPtr replaceInfo)
- {
- #pragma unused (addressSpaceID, replaceInfo)
- OSStatus err = noErr;
-
- return (err);
- }
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverOpenCmd ( AddressSpaceID addressSpaceID, ParmBlkPtr pb)
- {
- #pragma unused (addressSpaceID, pb)
- OSStatus err = noErr;
-
- // Let the world know we can do DriverGestalt calls
- DriverGestaltOn(gTheUTGlobals.drvrRefNum);
-
- return(err);
- }
-
- // Always run at task level, can allocate and move memory.
- OSStatus DriverCloseCmd (ParmBlkPtr pb)
- {
- #pragma unused (pb)
- OSStatus err = noErr;
-
- gTheUTGlobals.diskInDrive = false;
-
- // If an interrupt timer is set, cancel it!
- if( gInterruptTimer != 0 )
- {
- AbsoluteTime timeLeft;
-
- // Cancel any pending timers
- CancelTimer( gInterruptTimer, &timeLeft);
- gInterruptTimer = 0;
- }
-
- // If a command is pending, we should cancel it.
- // Since we currently have no way of informing the Class driver to abort,
- // we will wait for the class driver to tell us the command has finished.
- while( gTheUTGlobals.drivePB.theIOPB != nil );
-
- // Dequeue all drive volumes
- RemoveDrive(&gTheUTGlobals.theDrive);
-
- if(gItsTheDispatchTable != nil)
- {
- (void) ((gItsTheDispatchTable)->pStorageControl)(kControlEnableRemoval, nil);
- }
-
- // Let the world know we can no longer doDriverGestalt calls
- DriverGestaltOff(gTheUTGlobals.drvrRefNum);
-
- return (err);
- }
-
- // May run at interrupt level, CANNOT allocate or move memory.
- OSStatus DriverControlCmd ( AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandKind ioCommandKind,
- ParmBlkPtr pb)
- {
- #pragma unused ( addressSpaceID )
- OSStatus err = noErr;
- CntrlParamPtr pbPtr;
- DriveRecPtr drive = &gTheUTGlobals.theDrive;
-
- pbPtr = (CntrlParamPtr) pb;
-
-
- // Check if the control call is one that needs to use the parameter block
- // if so, do the initialization on it. There should be a check to make sure that
- // the PB is not in use before it is initialized.
- // This method will probably work because we shouldn't be getting these types of requests
- // while reads and writes are happening, but this is not guaranteed
- if ( (pbPtr->csCode == kVerify) || (pbPtr->csCode == kEject) || (pbPtr->csCode == kFormat)
- || ( pbPtr->csCode == 21315 ))
- {
- // Should be a check here to make sure that the parameter block is not in use
- BlockZero((Ptr) &gTheUTGlobals.drivePB, sizeof(DriveRequestPB));
-
- gTheUTGlobals.drivePB.theIOPB = nil;
- gTheUTGlobals.drivePB.ioCommandID = ioCommandID;
- gTheUTGlobals.drivePB.ioCommandKind = ioCommandKind;
- gTheUTGlobals.drivePB.retryCount = 0;
- gTheUTGlobals.drivePB.doWrite = false;
- }
-
- // Parse the control codes…
- switch(pbPtr->csCode)
- {
- case killCode:
- {
- // This driver does not support the killCode,
- // return back -1 as per TechNote DV 17: Sony Driver
- err = -1;
- }
- break;
-
- case kVerify: // Verify the media, this should only be called for floppies
- {
- if(gTheUTGlobals.theDrive.capacity == 0)
- {
- err = nsDrvErr; // no Media is inserted, return an error
- }
- else if( gTheUTGlobals.isFloppy == true )
- {
- UInt16 diskCapacity;
- UInt16 startBlock;
- UInt16 numberBlocks = 16;
- UInt8 *blockBuffer;
-
- diskCapacity = gTheUTGlobals.theDrive.capacity;
- blockBuffer = (UInt8 *) NewPtrSysClear(numberBlocks * gTheUTGlobals.theDrive.blockSize);
- if(blockBuffer == nil)
- {
- err = verErr;
- }
- else
- {
- for (startBlock = 0; startBlock<diskCapacity; startBlock+=numberBlocks)
- {
- gTheUTGlobals.doInternalReadWrite = true;
- err = ReadWriteBlock( &gTheUTGlobals, startBlock, numberBlocks,(Ptr) blockBuffer, false, false);
- gTheUTGlobals.doInternalReadWrite = false;
-
- // an Error has occured
- if ( err != noErr )
- {
- // report a verify error
- err = verErr;
- break;
- }
- }
- DisposePtr((Ptr) blockBuffer);
- }
- }
- else
- {
- err = noErr; // For the regular cartridge, just report noErr
- }
- }
- break;
-
- case kFormat:
- {
- if (gTheUTGlobals.isWriteProtected == true)
- {
- // check for write protect
- err = wPrErr;
- break;
- }
-
- if(gTheUTGlobals.theDrive.capacity == 0)
- {
- err = nsDrvErr; // no Media is inserted, return an error
- }
- else if( gTheUTGlobals.isFloppy == true )
- {
- gTheUTGlobals.currentExecutionState = kFormatStartState;
- FormatTheCartridge( &gTheUTGlobals );
- err = gTheUTGlobals.drivePB.status;
- }
- else
- {
- err = noErr; // For the regular cartridge, just report noErr
- }
- }
- break;
-
- case kEject:
- {
- // We get this call whenever a volume is put away (dragged to trash).
- Boolean hasMountedVolume = (MountedVolOfDrive(drive) != nil);
-
- if (!hasMountedVolume) // If no more mounted volumes…
- {
- gTheUTGlobals.currentExecutionState = kEjectStartState;
- EjectTheCartridge( &gTheUTGlobals );
- }
-
- }
- break;
-
- case kSetTagBuffer: // This is a floppy specific control call
- {
- err = controlErr; // Return a controlErr, since we do not support this call
- }
- break;
-
- case kTrackCache: // This is a floppy specific control call
- {
- err = controlErr; // The driver does not keep an internal write cache,
- // therefore report that we do not support this call
- }
- break;
-
- case kDriveIcon: // Return icon displayed during media initialization
- case kMediaIcon: // Return icon displayed on desktop for media
- {
- VolumeRecPtr vol = nil; // pointer to our volume record structure
-
- vol = GetVolume(drive, pbPtr->ioVRefNum, 0);
- if ( !vol ) // If we did not find a drive and volume
- {
- err = nsDrvErr; // report drive not found error
- break;
- }
-
- BlockMove(vol->mediaIconPtr, &gDriveIcon.LocationIcon, sizeof(DiskIcon));
-
- // Copy over the DriveInfo string from the global param block
- PStrCopy(gDriveIcon.LocationString, gTheUTGlobals.DriveInfoString);
-
- // Finally, return the pointer to the icon in csParam
- *(DriverLocationIcon**)pbPtr->csParam = &gDriveIcon;
-
- err = noErr; // clear any error from above
- }
- break;
-
- case kDriveInfo: // DRIVE INFO request (was from ATA maanger)
- {
- pbPtr->csParam[0] = 0; // Upper Word is always 0;
- pbPtr->csParam[1] = 0; // Clear Lower Word
-
- if( gTheUTGlobals.isFloppy == true )
- {
- // If we currently have a floppy loaded, return the following info
- pbPtr->csParam[1] = ( 1 << 11 ) // Drive cardinality (0 - primary, 1 - secondary)
- | ( 0 << 10 ) // Media removability ( 0 - removable, 1 - fixed )
- | ( 0 << 9 ) // Interface ( 0 - floppy, 1 - SCSI )
- | ( 1 << 8 ) // Location ( 0 - internal, 1 - external )
- // Bits 4,5,6,7 are reserved
- | 4; // Drive Type ( use 4 for SuperDrive for compatibility )
- }
- else if(gTheUTGlobals.theDrive.blockSize != 0)
- {
- // If we currently have a cartridge loaded, return the following info
- pbPtr->csParam[1] = ( 1 << 11 ) // Drive cardinality (0 - primary, 1 - secondary)
- | ( 0 << 10 ) // Media removability ( 0 - removable, 1 - fixed )
- | ( 1 << 9 ) // Interface ( 0 - floppy, 1 - SCSI )
- | ( 1 << 8 ) // Location ( 0 - internal, 1 - external )
- // Bits 4,5,6,7 are reserved
- | 1; // Drive Type ( use 1 for Unknown drive (Not a floppy) )
- }
-
- }
- break;
-
-
- case kDriverConfigureCode:
- {
- DriverConfigParam *configPtr; // local pointer to drive config structure
-
- configPtr = (DriverConfigParam *) pbPtr;
- switch(configPtr->driverConfigureSelector)
- {
- case kdgFlush:
- {
- // Since cache flushing differs between devices, this is not implemented in the sample driver.
- err = controlErr;
- }
- break;
-
- default:
- {
- err = controlErr;
- }
- break;
- }
- }
- break;
-
- case kcsSetBootPartitionCode: // Set Startup Partition
- {
- // Since there is currently no way to boot of USB,
- // this control call will report that it is not supported
- err = controlErr;
- }
- break;
-
- case kRegisterPartition: // Register New Partition
- {
- // PC Exchange will call this function when it wants to redefine a partition. It will
- // pass in the drive queue element pointer of the partition to redefine, the
- // new starting physical block offset, and the new block length.
-
- DrvQElPtr theDrvQEl; // drive queue element pointer
- VolumeRecPtr vol = nil; // pointer to our volume record structure
- UInt32 *altParams; // local pointer to alternate control parameters
-
- altParams = (UInt32 *)&pbPtr->csParam[0]; // alternate parameters
-
- err = nsDrvErr; // assume an invalid volume
- theDrvQEl = (DrvQElPtr) altParams[THE_DRIVE];
- if ( theDrvQEl ) // if valid queue element pointer
- {
- vol = GetVolume(drive, theDrvQEl->dQDrive, 0);
- if ( vol ) // and valid volume reference
- {
- vol->partoffset = altParams[THE_PHYS_START]; // new partition offset
- vol->curoffset = vol->partoffset; // current offset changes also
- vol->partblks = altParams[THE_PHYS_SIZE]; // new partition size
-
- UpdateQ(theDrvQEl->dQDrive, vol->partblks); // Update drive queue capacity
- vol->partmounted = true; // volume will be mounted by PCX
- err = noErr; // clear error
- }
- }
- }
- break;
-
- case kGetADrive: // Get A Drive (Create New Partition)
- {
- // PC Exchange calls this function to add a new partition. The new partition's DrvQElPtr is
- // returned. NOTE: If the driver handles multiple drives note that PC Exchange does not pass
- // in the physical drive number on which to create the new partition. However, the
- // DrvQElPtr stored at the pointer passed in is for another partition on the drive.
- UInt32 *altParams; // local pointer to alternate control parameters
-
- altParams = (UInt32 *)&pbPtr->csParam[0]; // alternate parameters
-
- if (!altParams[THE_VAR_QUEL]) // verify a valid queue element handle
- err = paramErr;
- else
- {
- // create a new volume record and DrvQEl associated with the physical drive.
- // The new volume starts at offset 0 and has no capacity yet. By default, the
- // partition will not have a partition map entry on the media.
- VolumeRecPtr vol = nil; // pointer to our volume record structure
-
- vol = CreateVolume(drive, NextPartitionID(drive), 0, 0 );
- if ( vol )
- {
- UInt16 volNumber;
-
- vol->vRefNum = NextQDrive(); // assign a logical drive number
- volNumber = vol->vRefNum;
-
- NativeAddDrive(gTheUTGlobals.drvrRefNum, volNumber,(DrvQElPtr) &vol->driveStatus.qLink);
-
- // Return the DrvQElPtr at the location passed in…
- *((DrvQElPtr*)altParams[THE_VAR_QUEL]) = (DrvQElPtr) &vol->driveStatus.qLink;
- }
- else
- err = controlErr;
- }
- }
- break;
-
- case kMediaPowerCSCode: // Set Power Mode
- {
- // The driver does not support power control modes
- // report back a controlErr.
- err = controlErr;
- }
- break;
-
- case 500:
- {
- AbsoluteTime theWait;
-
- IfDebugging("\pSet Dispatch Table");
- gItsTheDispatchTable = ( StorageClassDispatchTablePtr ) *((UInt32 *)(&pbPtr->csParam[0])); // The class's dispatch table
-
- (void) ((gItsTheDispatchTable)->pStorageControl)(kControlDisableRemoval, nil);
- theWait = DurationToAbsolute(durationSecond);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- err = SetInterruptTimer( &theWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
- }
- break;
-
- case 21315: // Disk copy format and copy
- {
- UInt16 theFormat;
- UInt8 *theDiskImage;
-
- //SysDebugStr("\pDiskCopy");
-
- if( gTheUTGlobals.isWriteProtected == true)
- {
- err = wPrErr; // disk is write protected
- break;
- }
-
- theFormat = pbPtr->csParam[0];
- theDiskImage = (UInt8 *) *((UInt32 *) &pbPtr->csParam[1]); // Extract the pointer to the data
- gTheUTGlobals.doInternalReadWrite = true;
- err = ReadWriteBlock( &gTheUTGlobals, 0, gTheUTGlobals.theDrive.capacity,(Ptr) theDiskImage, true, false );
- gTheUTGlobals.doInternalReadWrite = false;
-
- // an Error has occured
- if ( err != noErr )
- {
- // report an error
- err = paramErr;
- }
- }
- break;
-
- default:
- {
- err = controlErr;
- }
- break;
- }
-
- //SysDebugStr("\pEnd Control Call");
- return(err);
- }
-
- // May run at interrupt level, CANNOT allocate or move memory.
-
- OSStatus DriverStatusCmd ( AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandKind ioCommandKind,
- ParmBlkPtr pb)
- {
- #pragma unused (addressSpaceID, ioCommandID, ioCommandKind)
-
- OSStatus err = noErr;
- CntrlParamPtr pbPtr;
- DriveRecPtr drive = &gTheUTGlobals.theDrive;
-
- #if 0
- // This can be removed because this routine never invokes device access
- // and always complete immediately. If this a status call is added that
- // doesn't complete immediately, then this routine will have to guarantee
- // that the parameter block that it uses is not already in use.
- BlockZero((Ptr) &gTheUTGlobals.drivePB, sizeof(DriveRequestPB));
-
- gTheUTGlobals.drivePB.theIOPB = nil;
- gTheUTGlobals.drivePB.ioCommandID = ioCommandID;
- gTheUTGlobals.drivePB.ioCommandKind = ioCommandKind;
- gTheUTGlobals.drivePB.retryCount = 0;
- gTheUTGlobals.drivePB.doWrite = false;
- #endif
-
- pbPtr = (CntrlParamPtr) pb;
-
- // Finish processing the status call…
- switch(pbPtr->csCode)
- {
- case kReturnFormatList:
- {
- if( gTheUTGlobals.isFloppy == false )
- {
- err = statusErr;
- }
- else
- {
- typedef struct FormatList
- {
- UInt32 NumberBlock;
- UInt8 TSSValid : 1;
- UInt8 IsCurrentFormat : 1;
- UInt8 CanFormat : 1;
- UInt8 Density : 1;
- UInt8 NoSides : 4;
- UInt8 SecPerTrack;
- UInt16 NumberTracks;
- } FormatList;
-
- UInt8 returnNumber;
- UInt8 totalFormats = 2;
- FormatList theFormats[2];
-
- // Setup the Formats
- // Double Density Floppy Disk
- theFormats[0].NumberBlock = 1440;
- theFormats[0].TSSValid = 1;
- theFormats[0].Density = 0; // 0 means single density, 1 means Double Density
- theFormats[0].NoSides = 2;
- theFormats[0].SecPerTrack = 9;
- theFormats[0].NumberTracks = 80;
-
- // High Density Floppy Disk
- theFormats[1].NumberBlock = 2880;
- theFormats[1].TSSValid = 1;
- theFormats[1].Density = 1;
- theFormats[1].NoSides = 2;
- theFormats[1].SecPerTrack = 18;
- theFormats[1].NumberTracks = 80;
-
- if( drive->capacity < 0x600 )
- {
- theFormats[0].CanFormat = 0; // 0 means we can format this disk as 720K
- theFormats[1].CanFormat = 1; // 1 means we can not format this disk as 1.44M
- theFormats[0].IsCurrentFormat = 1; // 1 means 720K MFM Disk is installed
- theFormats[1].IsCurrentFormat = 0; // 0 means 1.44M MFM Disk is not installed
- }
- else
- {
- theFormats[0].CanFormat = 1; // 1 means we can not format this disk as 720K
- theFormats[1].CanFormat = 0; // 0 means we can format this disk as 1.44M
- theFormats[0].IsCurrentFormat = 0; // 0 means 720K MFM Disk is not installed
- theFormats[1].IsCurrentFormat = 1; // 1 means 1.44M MFM Disk is installed
- }
-
- returnNumber = *((UInt16 *) &pbPtr->csParam[0]);
- if( totalFormats < returnNumber )
- {
- returnNumber = totalFormats;
- }
-
- BlockCopy( (Ptr) &theFormats[0], (Ptr) (*((UInt32 *) &pbPtr->csParam[1])), sizeof(FormatList) * returnNumber);
- *((UInt16 *) &pbPtr->csParam[0]) = returnNumber;
- }
- }
- break;
-
- case kDriveStatus:
- {
- VolumeRecPtr vol = nil;
-
- vol = GetVolume(drive, pbPtr->ioVRefNum, 0);
- BlockMove(&vol->driveStatus, (UInt8 *) &pbPtr->csParam[0], sizeof(DrvSts));
- }
- break;
-
- case kMFMStatus:
- {
- if( gTheUTGlobals.isFloppy == false )
- {
- err = statusErr;
- }
- else
- {
- pbPtr->csParam[0] = -3; // PC Industry standard MFM (no GCR support)
- pbPtr->csParam[1] = -1; // MFM Disk installed
-
- if( drive->capacity < 0x600 )
- {
- pbPtr->csParam[2] = 0; // 720K MFM Disk installed
- }
- else
- {
- pbPtr->csParam[2] = -1; // 1.44M MFM Disk installed
- }
-
- pbPtr->csParam[3] = -5; // Generic PC Floppy Disk Controller
- }
- }
- break;
-
- case kDriverGestaltCode:
- {
- DriverGestaltParam *gestaltPtr; // local pointer to drive gestalt structure
- VolumeRecPtr vol = nil;
-
- vol = GetVolume(drive, pbPtr->ioVRefNum, 0);
- if (vol)
- drive = (DriveRecPtr) vol->drivePtr; // get its drive record
-
- gestaltPtr = (DriverGestaltParam *) pbPtr;
- switch(gestaltPtr->driverGestaltSelector)
- {
- case kdgVersion:
- {
- // Return information on the driver version
- NumVersion* numVersion;
-
- numVersion = GetDriverGestaltVersionResponse(gestaltPtr);
-
- numVersion->majorRev = kStorageHexMajorVers;
- numVersion->minorAndBugRev = kStorageHexMinorVers;
- numVersion->stage = kStorageReleaseStage;
- numVersion->nonRelRev = kStorageCurrentRelease;
- }
- break;
-
- case kdgDeviceType:
- {
- // Return the type of device--either floppy disk or removable disk
- DriverGestaltDevTResponse* deviceTypeResponse = GetDriverGestaltDevTResponse(gestaltPtr);
-
- if( gTheUTGlobals.isFloppy == true )
- {
- deviceTypeResponse->deviceType = kdgFloppyType;
- }
- else
- {
- deviceTypeResponse->deviceType = kdgRemovableType;
- }
- }
- break;
-
- case kdgInterface:
- {
- // Return the interface of the drive in ioVRefNum.
- DriverGestaltIntfResponse* interfaceResponse = GetDriverGestaltIntfResponse(gestaltPtr);
-
- interfaceResponse->interfaceType = 'USB ';
- }
- break;
-
- case kdgSync:
- {
- // Return true if the driver supports only synchronous behavior
- DriverGestaltSyncResponse* syncResponse = GetDriverGestaltSyncResponse(gestaltPtr);
-
- syncResponse->behavesSynchronously = false;
- }
- break;
-
- case kdgBoot:
- {
- // Return the ID of the boot device for PRAM storage
- if (!drive || !vol)
- err = nsDrvErr;
- else
- {
- // Since booting from USB is not yet supported, return statusErr.
- err = statusErr;
- }
- }
- break;
-
- case kdgWide:
- {
- // Return whether driver supports large volume addressing (> 4GByte)
- // Unless our cartridges are greater than 4 GB, we don't support
- // or need to support wide block addressing
- Boolean* response = GetDriverGestaltBooleanResponse(gestaltPtr);
-
- *response = false;
- }
- break;
-
- case kdgPurge: // Return if we can be closed and purged from memory.
- {
- DriverGestaltPurgeResponse* response = GetDriverGestaltPurgeResponse(gestaltPtr);
-
- // Currently the driver cannot be closed or purged once installed
- response->purgePermission = kmNoCloseNoPurge;
-
- response->purgeDriverPointer = (Ptr) nil;
- }
- break;
-
- case kdgSupportsSwitching:
- {
- // Return whether driver supports low power control call (csCode = 70h)
- *(GetDriverGestaltBooleanResponse(gestaltPtr)) = false;
- }
- break;
-
- case kdgSupportsPowerCtl:
- {
- // Return whether driver supports low power control call (csCode = 70h)
- *(GetDriverGestaltBooleanResponse(gestaltPtr)) = false;
- }
- break;
-
- case kdgAPI:
- {
- // Return whether driver supports PC-Exchange Control and Status calls
- // related to partitioning.
- DriverGestaltAPIResponse* apiResponse = GetDriverGestaltAPIResponse(gestaltPtr);
-
- apiResponse->partitionCmds = true;
- }
- break;
-
- case kdgFlush:
- {
- // Return whether driver supports the Cache flush Control call,
- // and whether the finder should tell us to flush our cache
- // Since cache flushing differs between devices, this is not implemented in the sample driver.
- DriverGestaltFlushResponse* response = GetDriverGestaltFlushResponse(gestaltPtr);
-
- response->canFlush = false;
- response->needsFlush = false;
- }
- break;
-
- case kdgEject:
- {
- // Return whether driver wants eject call for shutdown and restart
- // Eject on restart or shutdown
- DriverGestaltEjectResponse* response = GetDriverGestaltEjectResponse(gestaltPtr);
- response->ejectFeatures = 0L; // Clear both Dont Eject Bits, kShutDownDontEject and kRestartDontEject.
- }
- break;
-
- case kdgVMOptions:
- {
- // Return whether drive can be used for Virtual Memory
- // Don't support use of media for VM
- DriverGestaltVMOptionsResponse* response = GetDriverGestaltVMOptionsResponse(gestaltPtr);
- response->vmOptions = kAllowVMNoneMask;
- }
- break;
-
- case kdgMediaInfo:
- {
- // Return back specific information about our media
- DriverGestaltMediaInfoResponse* response = GetDriverGestaltMediaInfoResponse(gestaltPtr);
- //response->numberBlocks = vol->partblks;
- response->numberBlocks = gTheUTGlobals.theDrive.capacity;
- response->blockSize = gTheUTGlobals.theDrive.blockSize;
- if(gTheUTGlobals.theDrive.blockSize == 0)
- {
- response->mediaType = kMediaTypeNoMedia;
- }
- else
- {
- response->mediaType = kMediaTypeUnknown;
- }
- }
- break;
-
- /* Return a pointer to a IconFamily ('icns') data structure for */
- /* Disk Driver physical drive (formerly in csCode 22) in driverGestaltResponse. */
- case kdgPhysDriveIconSuite:
-
- /* Return a pointer to a IconFamily ('icns') data structure for */
- /* Disk Driver media (formerly in csCode 21) in driverGestaltResponse. */
- case kdgMediaIconSuite:
- {
- // If the media is currently a floppy, return a statusErr so the system will
- // handle the 3D Color icon information
- if( gTheUTGlobals.isFloppy == true )
- {
- if(FloppyMediaIconFamily == nil )
- {
- err = statusErr;
- }
- else
- {
- gestaltPtr->driverGestaltResponse = (UInt32) *FloppyMediaIconFamily;
- }
- }
- else
- {
- if(CartridgeMediaIconFamily == nil )
- {
- err = statusErr;
- }
- else
- {
- gestaltPtr->driverGestaltResponse = (UInt32) CartridgeMediaIconFamily;
- }
- }
- }
- break;
-
- case kdgMediaName:
- {
- /* Return a pointer to a pascal string describing the Disk Driver (formerly in csCode 21) in driverGestaltResponse. */
- gestaltPtr->driverGestaltResponse = (UInt32) &gTheUTGlobals.DriveInfoString;
- }
- break;
-
- default:
- err = statusErr; // unknown DriverGestalt selector
- }
- }
- break;
-
- case kcsGetBootPartitionStatus: // Is this the boot partition?
- {
- // Since USB drives don't support booting, always report false
- err = statusErr;
- }
- break;
-
- case kGetPartInfo:
- {
- // PC Exchange will call this function to get info on the specified partition.
- // Return the physical drive reference, the starting block offset, and
- // the partition ID (any relative non-zero reference).
-
- UInt32 *altParams; // alternate csParams as long words
- partInfoRecPtr thePartInfo;
- VolumeRecPtr vol = nil;
-
- altParams = (UInt32 *) &pbPtr->csParam[0]; // alternate parameters
- thePartInfo = (partInfoRecPtr)altParams[kPartInfoResponse];
- vol = GetVolume(drive, pbPtr->ioVRefNum, 0);
-
- // SCSIID is not defined for non-SCSI devices. For now we use the LUN only
- *((UInt32 *)&thePartInfo->SCSIID) = 0;
-
- thePartInfo->physPartitionLoc = vol->partoffset;
- thePartInfo->partitionNumber = vol->partitionNo;
- }
- break;
-
- case kMediaPowerCSCode:
- {
- // Driver does not support power control modes,
- // so just return a statusErr
- err = statusErr;
- }
- break;
-
- case 17494: // DiskCopy version supported
- {
- pbPtr->csParam[0] = 0x0410; // We support the Diskcopy 4.1 API
- }
- break;
-
- default: // Unrecognized status call
- {
- err = statusErr;
- }
- break;
- }
- //SysDebugStr("\pEnd Status Call");
-
- return(err);
- }
-
- // May run at interrupt level, CANNOT allocate or move memory.
-
- OSStatus DriverReadCmd ( AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandKind ioCommandKind,
- ParmBlkPtr pb)
- {
- #pragma unused ( addressSpaceID )
- OSStatus err = ioErr;
-
- if( gTheUTGlobals.diskInDrive == false)
- {
- err = ioErr;
- }
- else
- {
- //SysDebugStr("\pRead Call;g");
- // Clear out the Drive request PB
- BlockZero((Ptr) &gTheUTGlobals.drivePB, sizeof(DriveRequestPB));
-
- gTheUTGlobals.drivePB.theIOPB = pb;
- gTheUTGlobals.drivePB.ioCommandID = ioCommandID;
- gTheUTGlobals.drivePB.ioCommandKind = ioCommandKind;
- gTheUTGlobals.drivePB.retryCount = 0;
- gTheUTGlobals.drivePB.doWrite = false;
-
- err = DoReadWriteCommand( &gTheUTGlobals, false);
- }
- return(err);
- }
-
- // May run at interrupt level, CANNOT allocate or move memory.
-
- OSStatus DriverWriteCmd ( AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandKind ioCommandKind,
- ParmBlkPtr pb)
- {
- #pragma unused ( addressSpaceID )
- OSStatus err = ioErr;
-
- if( gTheUTGlobals.diskInDrive == false )
- {
- err = ioErr;
- }
- else
- {
- //SysDebugStr("\pWrite Call");
- // Clear out the Drive request PB
- BlockZero((Ptr) &gTheUTGlobals.drivePB, sizeof(DriveRequestPB));
-
- gTheUTGlobals.drivePB.theIOPB = pb;
- gTheUTGlobals.drivePB.ioCommandID = ioCommandID;
- gTheUTGlobals.drivePB.ioCommandKind = ioCommandKind;
- gTheUTGlobals.drivePB.retryCount = 0;
- gTheUTGlobals.drivePB.doWrite = true;
-
- err = DoReadWriteCommand( &gTheUTGlobals, true);
- }
-
- return(err);
- }
-
- // May run at interrupt level, CANNOT allocate or move memory.
-
- OSStatus DriverKillIOCmd (ParmBlkPtr pb)
- {
- #pragma unused (pb)
- OSStatus err = noErr;
-
- return (err);
- }
-
- void InstallInSleepQueue(OurSleepQRecPtr ourSleepQRec)
- {
- Boolean hasPMDispatch;
- SInt32 status;
-
- // To do most power management we must have the Power Manager Dispatch routines.
- if (Gestalt(gestaltPowerMgrAttr, &status) == 0)
- hasPMDispatch = (status & (1 << gestaltPMgrDispatchExists)) ? true : false;
-
- if (hasPMDispatch)
- {
- // Power Manager manages a spindown timer for the internal drive. When the
- // timer expires it calls all routines registered in the HD Queue, and then,
- // if PG&E is present (Powerbooks) it will turn off power to the drive.
- // If PG&E is not present (Desktops) Power Manager can't turn off power and
- // expects one of the queue routines to reduce drive power instead.
- // Therefore, if we manage the internal drive we should be in the HD Queue.
-
- ourSleepQRec->theSleepQRec.sleepQLink = nil;
- ourSleepQRec->theSleepQRec.sleepQType = sleepQType;
- ourSleepQRec->theSleepQRec.sleepQProc = NewSleepQProc( &SleepNotification);
- //ourSleepQRec->theSleepQRec.sleepQProc = (SleepQUPP) NewSleepQProc( &SleepNotification);
- ourSleepQRec->theSleepQRec.sleepQFlags = 0; // reserved
- ourSleepQRec->isInSleep = false;
- SleepQInstall( (SleepQRecPtr) ourSleepQRec );
- }
- }
-
- void RemoveFromSleepQueue(OurSleepQRecPtr ourSleepQRec)
- {
- Boolean hasPMDispatch;
- SInt32 status;
-
- // To do most power management we must have the Power Manager Dispatch routines.
- if (Gestalt(gestaltPowerMgrAttr, &status) == 0)
- hasPMDispatch = (status & (1 << gestaltPMgrDispatchExists)) ? true : false;
-
- if (hasPMDispatch)
- {
- SleepQRemove( (SleepQRecPtr) ourSleepQRec );
- }
- }
-
-
- long SleepNotification(long message, SleepQRecPtr sleepRec)
- {
- OurSleepQRecPtr ourSleepRec = (OurSleepQRecPtr) sleepRec;
- SInt32 response = noErr; // assume we accept command
-
- switch(message)
- {
- case dozeRequest: // ##### Request to doze ######
- case dozeDemand: // ##### Going to doze now ######
- case sleepRequest: // ##### Request to sleep ######
- case sleepDemand: // ##### Going to sleep now ######
- case sleepNow:
- ourSleepRec->isInSleep = true;
- break;
-
- case sleepWakeUp: // ##### Wakeup from sleep ######
- case sleepRevoke: // ##### Someone denied sleep ######
- case dozeWakeUp: // ##### Wakeup from doze ######
- ourSleepRec->isInSleep = false;
- break;
- }
-
- return(response);
- }
-
-
- OSStatus MountSecondaryInterrupt( void *p1, void *p2)
- {
- #pragma unused ( p1, p2 )
- OSStatus status;
- AbsoluteTime theWait;
- UInt32 classDriverStatus;
-
- IfDebugging("\pMountSecondaryInterrupt");
- gInterruptTimer = 0;
-
- if(gItsTheDispatchTable)
- {
- // Check if class driver is configured, if not setup another interrupt
- status = ((gItsTheDispatchTable)->pStorageStatus)(kStatusConfiguration, &classDriverStatus);
- if (status == noErr)
- {
- if ((classDriverStatus == kConfigureInProgress) || (gTheUTGlobals.theSleepQRec.isInSleep == true))
- {
- theWait = DurationToAbsolute(durationSecond);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- status = SetInterruptTimer( &theWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
-
- return noErr;
- }
- else if (classDriverStatus == kConfigureComplete)
- {
- gTheUTGlobals.currentExecutionState = kMountStartState;
- MountTheCartridge( &gTheUTGlobals );
- }
- }
- }
-
- return noErr;
- }
-
-
- void MountTheCartridge( void *theCurrentPB )
- {
- OSStatus err = noErr;
- AbsoluteTime oneSecondWait;
- DriveRec *drive;
- UTDriverGlobals *ourPB;
-
- ourPB = ((UTDriverGlobals *) theCurrentPB);
- drive = &ourPB->theDrive;
- oneSecondWait = DurationToAbsolute(durationSecond);
- //oneSecondWait = DurationToAbsolute(durationMillisecond * 20);
- switch (ourPB->currentExecutionState )
- {
- case kMountStartState:
- {
- ourPB->currentExecutionState = kMountTURDoneState;
- err = TUR( ourPB, &MountTheCartridge);
- }
- break;
-
- case kMountTURDoneState:
- {
- ourPB->currentExecutionState = kMountRequestSenseDoneState;
- err = RequestSense( ourPB, &MountTheCartridge);
- }
- break;
-
- case kMountRequestSenseDoneState:
- {
- if((ourPB->sense[12] == 0x00) && (ourPB->drivePB.executePB.status == noErr))
- {
- ourPB->currentExecutionState = kMountGetGeometryDoneState;
- ourPB->getCapacity.lastLogicalBlock = 0;
- ourPB->getCapacity.blockLength = 0;
- err = GetMediaGeometry( ourPB, &MountTheCartridge);
- }
- else
- {
- ourPB->currentExecutionState = kMountStartState;
- oneSecondWait = AddAbsoluteToAbsolute(UpTime(), oneSecondWait);
- err = SetInterruptTimer( &oneSecondWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
- err = noErr;
- }
- }
- break;
-
- case kMountGetGeometryDoneState:
- {
- ReadCapacityData *getGeometry;
-
- getGeometry = (ReadCapacityData *) &ourPB->getCapacity;
-
- drive->capacity = getGeometry->lastLogicalBlock+1; // Be sure to add the zero block in
- drive->blockSize = getGeometry->blockLength;
-
- if((drive->capacity == 0) || (drive->blockSize == 0))
- {
- //Find out why the capacity is zero
- ourPB->currentExecutionState = kMountCheckGetGeometryErrorDone;
- err = RequestSense( ourPB, &MountTheCartridge);
- break;
- }
-
- if( drive->capacity >0x0C00)
- {
- ourPB->isFloppy = false;
- }
- else
- {
- ourPB->isFloppy = true;
- }
-
- ourPB->diskInDrive = true;
-
- // Check to see if media is write protected
- ourPB->currentExecutionState = kMountCheckWriteProtectDoneState;
- err = CheckWriteProtect(ourPB, &MountTheCartridge);
- }
- break;
-
- case kMountCheckGetGeometryErrorDone:
- {
- if( (ourPB->sense[12] == 0x30) && (ourPB->sense[13] == 0x01))
- {
- // We have an unformatted cartridge, find out what format it can have
- ourPB->currentExecutionState = kMountReadPossibleCapacitiesDone;
- err = ReadFormatCapacity(ourPB, &MountTheCartridge);
- }
- else
- {
- ourPB->currentExecutionState = kMountStartState; // reset the machine
- oneSecondWait = AddAbsoluteToAbsolute(UpTime(), oneSecondWait);
- err = SetInterruptTimer( &oneSecondWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
- }
- }
- break;
-
- case kMountReadPossibleCapacitiesDone:
- {
- if( (ourPB->sense[3] >= 0x08) && (ourPB->sense[8] & 0x01 == 0x01))
- {
- // this is the maximum format for this cartridge
- drive->capacity = *((UInt32 *) &ourPB->sense[4]);
- drive->blockSize = *((UInt16 *) &ourPB->sense[10]);
-
- if( drive->capacity >0x0C00)
- {
- ourPB->isFloppy = false;
- }
- else
- {
- ourPB->isFloppy = true;
- }
-
- // Check to see if media is write protected
- ourPB->currentExecutionState = kMountCheckWriteProtectDoneState;
- err = CheckWriteProtect(ourPB, &MountTheCartridge);
- break;
- }
-
- // An error occurred. It could be:
- // 1. we didn't get a complete descriptor
- // 2. the drive doesn't recognize this media type
- // Reset and try again. ( Should we possibly eject the media instead??)
- ourPB->currentExecutionState = kMountStartState; // reset the machine
- oneSecondWait = AddAbsoluteToAbsolute(UpTime(), oneSecondWait);
- err = SetInterruptTimer( &oneSecondWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
- }
- break;
-
- case kMountCheckWriteProtectDoneState:
- {
- if ( ( ourPB->sense[3] & 0x80 ) != 0 )
- {
- ourPB->isWriteProtected = true;
- }
- else
- {
- ourPB->isWriteProtected = false;
- }
-
- ourPB->currentExecutionState = kMountPreventRemovalDoneState;
- err = PreventAllowRemoval(ourPB, true, &MountTheCartridge);
- }
- break;
-
- case kMountPreventRemovalDoneState:
- {
- // The device is now mounted, and the Media is locked in place.
- // There is nothing left for us to do, so just break.
- if (InstallDrive( drive, true ) == false)
- {
- gTheUTGlobals.currentExecutionState = kEjectStartState;
- EjectTheCartridge( &gTheUTGlobals );
- }
- }
- break;
- }
- }
-
- void EjectTheCartridge( void *theCurrentPB )
- {
- OSStatus err = noErr;
- UTDriverGlobals *ourPB;
-
- ourPB = ((UTDriverGlobals *) theCurrentPB);
- switch (ourPB->currentExecutionState )
- {
- case kEjectStartState:
- {
- ourPB->currentExecutionState = kEjectAllowRemovalDone;
- err = PreventAllowRemoval(ourPB, false, &EjectTheCartridge); // Allow for Ejects
- }
- break;
-
- case kEjectAllowRemovalDone:
- {
- ourPB->currentExecutionState = kEjectCartridgeDone;
- EjectCartridge(&gTheUTGlobals, EjectTheCartridge);
- }
- break;
-
- case kEjectCartridgeDone:
- {
- AbsoluteTime theWait;
- StorageExecuteCommandPB *commandPB;
- DriveRec *drive;
-
- drive = &ourPB->theDrive;
- RemoveDrive(drive);
- commandPB = &ourPB->drivePB.executePB; // use a pointer to the executePB field
- ourPB->drivePB.status = commandPB->status;
- if(commandPB->status == noErr)
- {
- ourPB->currentExecutionState = kMountStartState; // reset the machine
- theWait = DurationToAbsolute(durationSecond);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- SetInterruptTimer( &theWait, &MountSecondaryInterrupt, nil, &gInterruptTimer);
- }
-
- drive->capacity = 0;
- drive->blockSize = 0;
- ourPB->isFloppy = false;
- ourPB->diskInDrive = false;
- }
- break;
- }
- }
-
- OSStatus FormatCompletionInterrupt( void *p1, void *p2)
- {
- #pragma unused ( p1, p2 )
- gInterruptTimer = 0;
- gTheUTGlobals.currentExecutionState = kFormatWaitDoneState;
- FormatTheCartridge( &gTheUTGlobals );
- return noErr;
- }
-
- void FormatTheCartridge( void *theCurrentPB )
- {
- OSStatus err = noErr;
- AbsoluteTime oneSecondWait;
- DriveRec *drive;
- UTDriverGlobals *ourPB;
-
- ourPB = ((UTDriverGlobals *) theCurrentPB);
- drive = &ourPB->theDrive;
- oneSecondWait = DurationToAbsolute(durationSecond);
-
- switch (ourPB->currentExecutionState )
- {
- case kFormatStartState:
- {
- ourPB->currentExecutionState = kFormatDoneState;
- err = FormatFloppyCartridge( ourPB, &FormatTheCartridge);
- }
- break;
-
- case kFormatDoneState:
- {
- AbsoluteTime theWait;
-
- theWait = DurationToAbsolute(durationSecond*35);
- theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
- SetInterruptTimer( &theWait, &FormatCompletionInterrupt, nil, &gInterruptTimer);
- err = 1;
- }
- break;
-
- case kFormatWaitDoneState:
- {
- ourPB->currentExecutionState = kFormatRequestSenseDoneState;
- ourPB->drivePB.retryCount = 0;
- err = RequestSense( ourPB, &FormatTheCartridge);
- }
- break;
-
- case kFormatRequestSenseDoneState:
- {
- //SysDebugStr("\pRequest is done");
- if(ourPB->drivePB.executePB.status == noErr)
- {
- if(ourPB->sense[12] == 0x00)
- {
- ourPB->currentExecutionState = kFormatGetGeometryDoneState;
- ourPB->getCapacity.lastLogicalBlock = 0;
- ourPB->getCapacity.blockLength = 0;
- err = GetMediaGeometry( ourPB, &FormatTheCartridge);
- }
- else
- {
- // The format has failed, inform the OS
- err = controlErr;
- }
- }
- else
- {
- if (ourPB->drivePB.retryCount < kFormatRequestSenseRetryCount)
- {
- ourPB->currentExecutionState = kFormatRequestSenseDoneState;
- ourPB->drivePB.retryCount += 1;
- err = RequestSense( ourPB, &FormatTheCartridge);
- }
- else
- {
- // The format has failed, inform the OS
- ourPB->drivePB.retryCount = 0;
- err = controlErr;
- }
- }
- }
- break;
-
- case kFormatGetGeometryDoneState:
- {
- ReadCapacityData *getGeometry;
-
- getGeometry = (ReadCapacityData *) &ourPB->getCapacity;
-
- drive->capacity = getGeometry->lastLogicalBlock+1; // Be sure to add the zero block in
- drive->blockSize = getGeometry->blockLength;
-
- if( (ourPB->drivePB.executePB.status != noErr) || (drive->capacity == 0) || (drive->blockSize == 0))
- {
- // The format has failed, inform the OS
- err = controlErr;
- break;
- }
-
- if( drive->capacity >0x0C00)
- {
- ourPB->isFloppy = false;
- }
- else
- {
- ourPB->isFloppy = true;
- }
-
- ourPB->diskInDrive = true;
- }
- break;
- }
-
- ourPB->drivePB.status = err;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
-
-
- OSStatus CheckWriteProtect(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- IfDebugging("\pCheck Write Protect");
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB)); // clear out the PB we will send
- BlockZero((Ptr) &theCurrentPB->sense[0], 8);
-
- commandPB->cdb[0] = kCmdModeSense;
- commandPB->cdb[8] = 0x08;
- commandPB->flags = kStorageDataIn; // -> Expect a data in transfer
- commandPB->userBuffer = (Ptr) &theCurrentPB->sense[0]; // -> Pointer to user buffer
- commandPB->expectedCount = 8; // -> Expected number of bytes to transfer
- commandPB->completionProc = ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
- OSStatus TUR(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- IfDebugging("\pTUR");
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB)); // clear out the PB we will send
-
- commandPB->flags = kStorageNoData;
- commandPB->completionProc = ourCompletion;
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
- OSStatus RequestSense(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = (StorageExecuteCommandPB *)&theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
- BlockZero((Ptr) &theCurrentPB->sense[0], sizeof(kSenseDataSize));
-
- commandPB->cdb[0] = kCmdRequestSense;
- commandPB->cdb[4] = kSenseDataSize;
- commandPB->flags = kStorageDataIn; // -> Expect a data in transfer
- commandPB->userBuffer = (Ptr) &theCurrentPB->sense[0]; // -> Pointer to user buffer
- commandPB->expectedCount = kSenseDataSize; // -> Expected number of bytes to transfer
- commandPB->completionProc = ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
- OSStatus GetMediaGeometry(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- IfDebugging("\pGetMediaGeometry");
-
- if (gItsTheDispatchTable)
- {
- ReadCapacityData *getGeometry;
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
- getGeometry = &theCurrentPB->getCapacity;
-
- getGeometry->lastLogicalBlock = 0;
- getGeometry->blockLength = 0;
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
-
- commandPB->cdb[0] = kCmdReadCapacity;
- commandPB->flags = kStorageDataIn; // -> Expect a data in transfer
- commandPB->userBuffer = (Ptr) getGeometry; // -> Pointer to user buffer
- commandPB->expectedCount = sizeof(ReadCapacityData); // -> Expected number of bytes to transfer
- commandPB->completionProc = ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
-
- OSStatus ReadFormatCapacity(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- IfDebugging("\pReadFormatCapacity");
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
-
- commandPB->cdb[0] = kCmdReadFormatCapacities;
- commandPB->cdb[7] = 0;
- commandPB->cdb[8] = 0x0C;
- commandPB->flags = kStorageDataIn; // -> Expect a data in transfer
- commandPB->userBuffer = (Ptr) &theCurrentPB->sense[0]; // -> Pointer to user buffer
- commandPB->expectedCount = 0x0C; // -> Expected number of bytes to transfer
- commandPB->completionProc = (StorageClassCompletionProcPtr) ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
-
- OSStatus FormatFloppyCartridge(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- IfDebugging("\pFormatFloppyCartridge");
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
- BlockZero((Ptr) &theCurrentPB->sense[0], 0x0C);
-
- // Set up the data going out
- // First set up the Defect List Header
- theCurrentPB->sense[0] = 0;
- theCurrentPB->sense[1] = 0;
- theCurrentPB->sense[2] = 0;
- theCurrentPB->sense[3] = 0x08;
-
- *((UInt32 *) &theCurrentPB->sense[4]) = theCurrentPB->theDrive.capacity;
- *((UInt16 *) &theCurrentPB->sense[10]) = theCurrentPB->theDrive.blockSize;
-
- commandPB->cdb[0] = kCmdFormat;
- commandPB->cdb[1] = 0x17;
- commandPB->flags = kStorageDataOut; // -> Expect a data out transfer
- commandPB->userBuffer = (Ptr) &theCurrentPB->sense[0]; // -> Pointer to user buffer
- commandPB->expectedCount = 0x0C; // -> Expected number of bytes to transfer
- commandPB->completionProc = (StorageClassCompletionProcPtr) ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
-
- OSStatus EjectCartridge(UTDriverGlobals *theCurrentPB, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
-
- commandPB->cdb[0] = kCmdStartStopUnit;
- commandPB->cdb[4] = 0x02; // Unload the Media
- commandPB->flags = kStorageNoData; // -> Expect a data in transfer
- commandPB->userBuffer = nil; // -> Pointer to user buffer
- commandPB->expectedCount = 0; // -> Expected number of bytes to transfer
- commandPB->completionProc = (StorageClassCompletionProcPtr) ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
-
- OSStatus PreventAllowRemoval(UTDriverGlobals *theCurrentPB, Boolean preventRemoval, StorageClassCompletionProcPtr ourCompletion)
- {
- OSStatus status = noErr;
-
- if (gItsTheDispatchTable)
- {
- StorageExecuteCommandPB *commandPB;
-
- commandPB = &theCurrentPB->drivePB.executePB; // use a pointer to the executePB field
-
- BlockZero(commandPB, sizeof(StorageExecuteCommandPB));
-
- commandPB->cdb[0] = kCmdPreventAllowRemoval;
- if ( preventRemoval == true )
- {
- commandPB->cdb[4] = 0x01; // Prevent Media Removal
- }
- else
- {
- commandPB->cdb[4] = 0x00; // Allow Media Removal
- }
-
- commandPB->flags = kStorageNoData; // -> Expect a data in transfer
- commandPB->userBuffer = nil; // -> Pointer to user buffer
- commandPB->expectedCount = 0; // -> Expected number of bytes to transfer
- commandPB->completionProc = (StorageClassCompletionProcPtr) ourCompletion; // -> Completion routine
-
- status = (gItsTheDispatchTable->pStorageExecuteCmd)(commandPB);
- }
-
- return status;
- }
-
-
- /* ---------------------Supporting Functions below this point -------------------------- */
- //------------------------------------------------------------------------------
- // Function: DRVRPrime
- // Description: This is the ATA driver PRIME call that performs
- // reading and writing to the device.
- //
- // Input: ioPB = Pointer to caller's I/O parameter block
- // dce = Pointer to Device Control Entry (DCE)
- // Output: A status code is returned.
- //-------------------------------------------------------------------------------
- OSStatus DoReadWriteCommand( UTDriverGlobals *theDriverPB, Boolean doWrite )
- {
- OSStatus err;
- UInt32 startingBlock, numBlocks;
- VolumeRecPtr vol;
- IOParamPtr iopb;
- DriveRecPtr drive;
-
- drive = &theDriverPB->theDrive;
- iopb = (IOParamPtr) theDriverPB->drivePB.theIOPB;
-
- // Find the associated volume and drive records required for the request.
- vol = GetVolume(drive, iopb->ioVRefNum, 0); // Get the volume record requested
-
- //if (vol) // if we have a volume
- // drive = (DriveRecPtr)vol->drivePtr; // get its drive record
- //else // assume request if for a physical drive
- if (!vol) // if we have a volume
- {
- if (drive) // if physical drive matches…
- {
- vol = drive->nextVol;
- if (vol) // and a volume exists for it…
- {
- if (vol->curoffset) // and not doing physical addressing…
- {
- vol = 0; // the volume is invalid
- }
- }
- }
- }
-
- if (!vol || !drive) // Abort if we don't have both drive and volume records
- return(nsDrvErr);
-
- //................................................................................
- // A usable drive and volume exists. Continue processing the request…
-
- // Compute the starting block address for the request. We accept
- // only the normal 32 bit address and not the new 'Large Volume (64 bit) Addressing'.
- //SysDebugStr("\pCalculate the Read.");
- startingBlock = (UInt32)((iopb->ioPosOffset)/(drive->blockSize));
- numBlocks = (iopb->ioReqCount)/(drive->blockSize);
-
- if (doWrite && vol->driveStatus.writeProt)
- {
- // check for write protect
- err = wPrErr;
- }
- else if (iopb->ioReqCount & ((drive->blockSize) - 1))
- {
- // Verify if request is a multiple of the drives blocksize
- err = paramErr;
- }
- else if ( ( startingBlock + numBlocks ) > ((vol->curoffset) ? vol->partblks : drive->capacity))
- {
- // Verify if request is within range with respect to doing physical or logical I/O.
- // Access is limited to partition range (logical I/O) if curoffset is non-zero.
- err = paramErr;
- }
- else if ((iopb->ioPosMode & rdVerify) && !doWrite)
- {
- // If Read-Verify mode, this is not efficient with disks so we simply pretend we did it.
- iopb->ioActCount = iopb->ioReqCount;
- iopb->ioPosOffset += iopb->ioActCount;
- err = noErr;
- }
- else // Do the read or write
- {
- startingBlock += vol->curoffset; // add in the partition offset
- err = ReadWriteBlock( theDriverPB, startingBlock, numBlocks, iopb->ioBuffer, doWrite, true );
- }
-
- return err;
- }
-
- //------------------------------------------------------------------------------
- // Function: ReadWriteBlock
- //
- // Description: Low level read/write block on the media with retries.
- //
- // Input: drive: Pointer to physical drive record
- // blockAddr: Starting block address
- // numBlocks: Number of blocks to read/write
- // buffer: Pointer to buffer
- // doWrite: 1 = write, 0 = read
- //
- // Output: true if successful, false if not
- //-------------------------------------------------------------------------------
- OSStatus ReadWriteBlock( UTDriverGlobals *theDriverPB, UInt32 startBlock, UInt32 numBlocks, Ptr buffer, Boolean doWrite, Boolean doAsync)
- {
- StorageExecuteCommandPBPtr theReadWriteRequest;
- UInt32 driveBlockSize;
- volatile OSStatus status = noErr;
-
- IfDebugging("\p…ReadWriteBlock");
- theDriverPB->drivePB.status = noErr;
- driveBlockSize = theDriverPB->theDrive.blockSize;
- theReadWriteRequest = &(theDriverPB->drivePB.executePB);
-
- BlockZero(theReadWriteRequest, sizeof(StorageExecuteCommandPB)); // clear out the PB we will send
- theReadWriteRequest->userBuffer = buffer; // -> Pointer to user buffer
- theReadWriteRequest->expectedCount = numBlocks*driveBlockSize; // -> Expected number of bytes to transfer
-
- theReadWriteRequest->completionProc = (StorageClassCompletionProcPtr) ReadWriteCompletion; // -> Completion routine
- theReadWriteRequest->actualCount = 0; // <- Actual number of bytes transferred
- theReadWriteRequest->status = 0; // <- Result of operation
-
- if(doWrite)
- {
- theReadWriteRequest->cdb[0] = kCmdWrite;
- theReadWriteRequest->flags = kStorageDataOut; // -> Expect a data out transfer
- }
- else
- {
- theReadWriteRequest->cdb[0] = kCmdRead;
- theReadWriteRequest->flags = kStorageDataIn; // -> Expect a data in transfer
- }
-
- // Set the starting block in the CDB
- theReadWriteRequest->cdb[2] = (startBlock >> 24) & 0xff;
- theReadWriteRequest->cdb[3] = (startBlock >> 16) & 0xff;
- theReadWriteRequest->cdb[4] = (startBlock >> 8) & 0xff;
- theReadWriteRequest->cdb[5] = startBlock & 0xff;
-
- // Set the Block Count in the CDB
- theReadWriteRequest->cdb[7] = (numBlocks >> 8) & 0xff;
- theReadWriteRequest->cdb[8] = numBlocks & 0xff;
-
- status = ((gItsTheDispatchTable)->pStorageExecuteCmd)( theReadWriteRequest );
-
- theDriverPB->drivePB.status = status;
-
- if(status != 1)
- {
- theDriverPB->drivePB.theIOPB = nil;
- }
- else
- {
- if(doAsync == false)
- {
- while ( status == 1 )
- {
- status = theDriverPB->drivePB.status;
- }
- }
- }
-
- return status;
- }
-
-
- void ReadWriteCompletion( void *theDriverPB )
- {
- OSStatus status;
- UTDriverGlobals *ourPB;
- Boolean wasWrite;
-
- //SysDebugStr("\pReadWriteCompletion;g");
- ourPB = (UTDriverGlobals *) theDriverPB;
- status = ourPB->drivePB.executePB.status;
- wasWrite = ((ourPB->drivePB.executePB.flags & kStorageDataOut) == kStorageDataOut);
- if(ourPB->doInternalReadWrite == false)
- {
- IOParamPtr iopb;
-
- iopb = (IOParamPtr) ourPB->drivePB.theIOPB;
-
- if( status == noErr )
- {
- if( wasWrite == true )
- {
- // It was a write, do a Request sense to determine if any
- // errors occurred.
- status = RequestSense( ourPB, &WriteRequestSenseCompletion);
-
- if( status != 1)
- {
- // An error occurred while trying to do the Request sense,
- // return an ioErr to the system.
- iopb->ioActCount = 0;
-
- // Set the status in the DriverPB last, this way if there is an immediate command,
- // It won't think the command is done till after our processing.
- ourPB->drivePB.status = ioErr;
-
- // Signal completion of the command to the operating system
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
- }
- else
- {
- // This was a read command, and no errors occurred, finish the IO request and
- // return to the system.
- iopb->ioActCount = iopb->ioReqCount;
-
- // Set the status in the DriverPB last, this way if there is an immediate command,
- // It won't think the command is done till after our processing.
- ourPB->drivePB.status = noErr;
-
- // Signal completion of the command to the operating system
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
- }
- else
- {
- // An error occurred on the command, do a Request sense to be certain any
- // USB Device stalls are cleared.
- status = RequestSense( ourPB, &RequestSenseOnErrorCompletion);
-
- if( status != 1)
- {
- // An error occurred while trying to do the Request sense,
- // return an ioErr to the system.
- iopb->ioActCount = 0;
-
- // Set the status in the DriverPB last, this way if there is an immediate command,
- // It won't think the command is done till after our processing.
- ourPB->drivePB.status = ioErr;
-
- // Signal completion of the command to the operating system
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
- }
- }
- else
- {
- // If this is an internal command, this is all we care about
- ourPB->drivePB.status = status;
- }
-
- IfDebugging("\p…ReadWriteBlock Done");
- }
-
- void WriteRequestSenseCompletion( void *theDriverPB )
- {
- OSStatus status;
- UTDriverGlobals *ourPB;
- IOParamPtr iopb;
-
- ourPB = (UTDriverGlobals *) theDriverPB;
- status = ourPB->drivePB.executePB.status;
- iopb = (IOParamPtr) ourPB->drivePB.theIOPB;
-
- if( status == noErr )
- {
- if( ( ourPB->sense[2] & 0x0F !=0 ) && ( ourPB->sense[2] & 0x0F !=1 ))
- {
- // An error has been reported back in the sense key, return
- // an ioErr to the system.
- iopb->ioActCount = 0;
- ourPB->drivePB.status = ioErr;
- }
- else
- {
- // No errors has been reported back in the sense key, return
- // a noErr to the system.
- iopb->ioActCount = iopb->ioReqCount;
- ourPB->drivePB.status = noErr;
- }
- }
- else
- {
- // Errors occurred on the Request sense report an
- // ioErr back to the system
- iopb->ioActCount = 0;
- ourPB->drivePB.status = ioErr;
- }
-
- // Signal completion of the command to the operating system
- //SysDebugStr("\pWriteReqSenseFinishCommand");
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
-
- void RequestSenseOnErrorCompletion( void *theDriverPB )
- {
- UTDriverGlobals *ourPB;
- IOParamPtr iopb;
-
- ourPB = (UTDriverGlobals *) theDriverPB;
- iopb = (IOParamPtr) ourPB->drivePB.theIOPB;
-
- // An error occurred on the initial command, and no error occurred on the RequestSense
- if( (ourPB->drivePB.retryCount < kReadWriteRetryCount) && (ourPB->drivePB.executePB.status == noErr))
- {
- OSStatus err;
- // We have not yet exceeded the retry count, so try the operation again
- // Increment our retry counter
- ourPB->drivePB.retryCount += 1;
-
- // Send the command out again
- err = DoReadWriteCommand( ourPB, ourPB->drivePB.doWrite);
-
- if ( err !=1 )
- {
- iopb->ioActCount = 0;
- ourPB->drivePB.status = ioErr;
-
- // Signal completion of the command to the operating system
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
- }
- else
- {
- // Since we only get here if an error occurred on the orignal
- // command, and the Request Sense was to clear any device stalls.
- // We will always report back an ioErr to the system.
- iopb->ioActCount = 0;
- ourPB->drivePB.status = ioErr;
-
- // Signal completion of the command to the operating system
- ourPB->drivePB.theIOPB = nil;
- FinishCommandProcessing(ourPB->drivePB.ioCommandID, ourPB->drivePB.ioCommandKind, ourPB->drivePB.status);
- }
- }
-
-
- //------------------------------------------------------------------------------
- // Function: GetVolume
- //
- // Description: Searches for the volume record with the specified vRefNum and
- // returns its VolumeRecPtr. Optionally, partitionNum
- // can be use as search keys if vRefNum is zero.
- //
- // Input: drive: the pointer to the DriveRec
- // vRefNum: the volume's reference number
- // partitionNum: the volume's partition number
- //
- // Output: pointer to volume record if found, nil if not found
- //-------------------------------------------------------------------------------
- VolumeRecPtr GetVolume(DriveRecPtr drive, UInt16 vRefNum, UInt32 partitionNum)
- {
- VolumeRecPtr vol = nil;
- Boolean found;
-
- // Search all volume records for one matching the search key
-
- vol = drive->nextVol; // first volume pointer
-
- while (vol)
- {
- found = (vRefNum) ? (vol->vRefNum == vRefNum) : (vol->partitionNo == partitionNum);
-
- if (found)
- return(vol); // found the partition
- else
- vol = (VolumeRecPtr)vol->nextVol; // otherwise, get next volume pointer
- }
-
- return(vol); // nil if volume not found
- }
-
-
- //------------------------------------------------------------------------------
- // Function: CreateVolume
- //
- // Description: This function creates a volume record for the specified drive.
- // The volume is appended to the drive's volume queue and a logical
- // logical drive is installed in the system drive queue. It is
- // assumed the volume is not write protected, drive is installed,
- // and the media is installed.
- //
- // Input: drive: pointer to the drive record of the volume to create
- // partitionID: the volume's partition ID
- // volSize: size of the volume in blocks
- // volOffset: block offset of volume on drive
- //
- // Output: Returns nil pointer if fails, else pointer to volume record
- //
- // NOTE: Assumes all inputs are valid!
- //-------------------------------------------------------------------------------
- VolumeRecPtr CreateVolume(DriveRecPtr drive, UInt32 partitionID, UInt32 volSize, UInt32 volOffset )
- {
- register VolumeRecPtr vol;
- VolumeRecPtr* volHandle;
- Boolean volInQueue = false;
-
- // When a volume is offlined by the system (greyed desktop icon) it is still
- // being used and its associated DrvQEl must remain. Thus, its volume and
- // physical drive record also must remain. So, when new media is inserted
- // we need to check for these structures and reuse them before creating new ones.
- // The structures can be reused since the file system verifies the volume.
-
- if( drive->nextVol == nil)
- {
- // Make sure the drive's volume queue points to the volume
- vol = &gTheUTGlobals.theVolume;
- }
- else
- {
- // Search for a volume record for the volume (partition) to be created…
- vol = GetVolume(drive, 0, partitionID);
-
- if (vol) // if record exists for this volume…
- {
- volInQueue = true; // remember volume is already in queue
-
- if (vol->driveStatus.diskInPlace) // if volume is already online…
- vol = nil; // we shouldn't be here - fall thru
- }
- else // need to create volume record
- {
- vol = (VolumeRecPtr) PoolAllocateResident(sizeof(VolumeRec), true); // Allocate storage for record
- }
- }
-
- if (vol) // if a volume record is valid…
- {
- if( gTheUTGlobals.isFloppy == true)
- {
- vol->driveStatus.track = 80; // Sectors on a MFM disk
- vol->driveStatus.sides = -1; // -1 means double sided floppy
- }
- else
- {
- vol->driveStatus.track = 0; // Only used on floppys
- vol->driveStatus.sides = 0; // Only used on floppys
- }
-
- if( gTheUTGlobals.isWriteProtected == true)
- {
- vol->driveStatus.writeProt = 0x80; // disk is write protected
- }
- else
- {
- vol->driveStatus.writeProt = 0; // not write protected yet
- }
- vol->driveStatus.diskInPlace = 1; // Ejectable Disk
- vol->driveStatus.installed = 1; // drive is installed
- vol->driveStatus.dQFSID = 0; // File Manager's volume type
- if( gTheUTGlobals.isFloppy == true)
- {
- DrvSts *theDriveStatus;
-
- theDriveStatus = (DrvSts *) &vol->driveStatus;
- theDriveStatus->qType = 0; // This is a floppy drive status structure
- theDriveStatus->twoSideFmt = -1; // after 1st rd/wrt: 0=1 side, -1=2 side
- theDriveStatus->needsFlush = -1; // -1 for MacPlus drive
- theDriveStatus->diskErrs = 0; // soft error count
-
- vol->mediaIconPtr = (Ptr) AppleFloppyMediaIcon; // media icon for floppies
- }
- else
- {
- vol->driveStatus.qType = 1; // both dQDrvSz and dQDrvSz2 are used
- vol->driveStatus.driveSize = (UInt16) volSize; // volume size in blocks
- vol->driveStatus.driveS1 = (UInt16) (volSize >> 16);
-
- vol->mediaIconPtr = (Ptr) &CartridgeIcon; // media icon for cartridge
- }
-
-
- vol->mountthispart = false; // don't mount this volume,
- vol->partmounted = false; // it's not mounted yet,
- vol->partitionNo = partitionID; // save the partition ID
-
- // Save volume's block offset and set its access mode by setting curoffset to the
- // same (access is relative to partition offset if curoffset is non-zero, else physical)
- vol->curoffset = volOffset; // block offset of volume
- vol->partoffset = volOffset; // partition offset
- vol->partblks = volSize; // save size for our use also
- vol->drivePtr = (Ptr) drive; // pointer to vol's physical drive
- // If this record is not in our volume list yet, finish initializing and insert
- if (!volInQueue) // If not in the volume queue…
- {
- vol->driveStatus.qLink = nil; // initialize system queue link
- vol->nextVol = nil; // no link to next volume yet
-
- // Find the end of the drive's volume queue and link in the new volume record.
- volHandle = &(drive->nextVol); // point to start of drive's volume queue
- while (*volHandle) // search for end of volume queue…
- {
- volHandle = (VolumeRecPtr*)&((*volHandle)->nextVol);
- }
-
- *volHandle = vol; // at end of queue, insert volume
- }
-
- drive->numVolumes++; // update number of drive volumes
- }
- return(vol);
- }
-
-
- //------------------------------------------------------------------------------
- // Function: InstallVolumes
- // Description: Searches for partitions on the media and installs them as
- // volumes for the associated drive. Assumes the drive does
- // not have any volumes installed yet.
- //
- // Input: theDrive: pointer to drive record
- // mountVols: true means to mount the drive's partitions
- //
- //-------------------------------------------------------------------------------
- void InstallVolumes(DriveRecPtr theDrive, Boolean mountVols)
- {
- VolumeRecPtr vol = nil;
-
- // If the driver is going to support partitions, this is were the media should be
- // scanned to see if there are any valid HFS or DOS partitions.
-
- // If no valid paritions are found, or partitions are not support, the following code
- // will create a volume of the entire media capacity, post a disk inserted
- // event and let the File System Manager try and figure it out. Note we post a disk
- // inserted event rather than notifying FSM so if the media is not recognized (because
- // it's unformatted or the correct file system is not installed) the system will prompt
- // with a "This is not a Macintosh disk…" message. If we call FSM instead, the user will
- // not be prompted when the media is unformatted. This provides a way to format media.
-
- if (theDrive->numVolumes == 0) // if no partitions were found, or are not supported
- {
- IfDebugging("\ptheDrive->numVolumes == 0");
- vol = CreateVolume(theDrive, 1, theDrive->capacity, 0);
- if (vol)
- {
- vol->mountthispart = true; // post disk inserted event later
- }
- }
-
- // Add the remaining volumes to the drive queue…
- vol = theDrive->nextVol; // first volume of the drive
- while (vol)
- {
- if ((vol->mountthispart == true) || (mountVols == false))
- {
- UInt16 volNumber;
-
- vol->vRefNum = NextQDrive(); // assign a logical drive number
- volNumber = vol->vRefNum;
-
- NativeAddDrive(gTheUTGlobals.drvrRefNum, volNumber,(DrvQElPtr) &vol->driveStatus.qLink);
- }
-
- vol = (VolumeRecPtr)vol->nextVol; // point to the next volume
- }
- }
-
-
- //------------------------------------------------------------------------------
- // Function: RemoveVolume
- // Description: Deletes a volume and its record
- // Input: drvRec: pointer to physical drive record of volume
- // volRef: Volume reference
- //-------------------------------------------------------------------------------
- void RemoveVolume(DriveRecPtr drvRec, UInt16 volRef)
- {
- VolumeRecPtr* pvHandle = &(drvRec->nextVol);
- VolumeRecPtr pvPtr = *pvHandle;
-
- while (pvPtr)
- {
- if (pvPtr->vRefNum == volRef) // found the volume record
- {
- Dequeue((QElemPtr) &(pvPtr->driveStatus.qLink), GetDrvQHdr()); // remove from drive queue
- *pvHandle = (VolumeRecPtr)(pvPtr->nextVol); // remove it from the linked list
- if (pvPtr == &gTheUTGlobals.theVolume)
- {
- BlockZero((Ptr) &gTheUTGlobals.theVolume, sizeof(VolumeRec));
- }
- else
- {
- PoolDeallocate( pvPtr ); // release its memory
- }
- drvRec->numVolumes--; // decrement number of drive volumes
- break;
- }
-
- pvHandle = (VolumeRecPtr*)&(pvPtr->nextVol); // save pointer to pv pointer
- pvPtr = (VolumeRecPtr)pvPtr->nextVol; // point to next pv
- }
- }
-
-
- //------------------------------------------------------------------------------
- // Function: InstallDrive
- //
- // Description: Installs a physical drive and its volumes under the driver's
- // control. The driver determines if the drive is one it can
- // manage, and if so, creates and initializes the drive's record,
- // sets the drives operating mode and options, and mounts its
- // partitions to the system.
- //
- // Input: drvNum: physical drive reference
- // mountVols: true means to mount drive's partitions
- //
- // Output: true if successful, false if not
- //-------------------------------------------------------------------------------
- Boolean InstallDrive(DriveRecPtr theDrive, Boolean mountVols)
- {
- // Initialize variables associated with the new drive.
- theDrive->numVolumes = 0; // no partitions yet
-
- //..............................................................................
- // Search for file system partitions on the media and install them as volumes
- // of this drive. If no volumes, the drive must be considered unusable.
- InstallVolumes(theDrive, mountVols);
-
- if (theDrive->numVolumes)
- {
- OSErr theErr;
-
- theErr = MountVolumes( theDrive );
- if(theErr != noErr)
- {
- // For some reason, the disk could not be mounted,
- // We should eject and let the user decide whether to try again.
- gTheUTGlobals.currentExecutionState = kEjectStartState;
- EjectTheCartridge( &gTheUTGlobals );
- }
- }
- else // Abort if no volumes installed for drive
- {
- return(false);
- }
-
- return(true);
- }
-
-
- //------------------------------------------------------------------------------
- // Function: RemoveDrive
- // Description: Removes a physical drive and its volumes from our control
- //
- //-------------------------------------------------------------------------------
- void RemoveDrive(DriveRecPtr theDrivePtr)
- {
- VolumeRecPtr vol;
- UInt16 vrefnum;
-
- if (theDrivePtr) // If the drive exists…
- {
- while (theDrivePtr->nextVol) // dequeue all volumes on the drive…
- {
- vol = theDrivePtr->nextVol; // get volume
- vrefnum = vol->vRefNum; // get its refnum
- RemoveVolume(theDrivePtr, vrefnum); // delete volume from our queue
- }
- }
- }
-
-
- //------------------------------------------------------------------------------
- // Function: NextQDrive
- //
- // Description: Returns the next unused logical drive number from the system
- // Drive Queue. The Drive Queue is searched starting with a
- // logical drive number 8.
- //
- // Input: none
- //
- // Output: The highest Drive Queue drive number + 1
- //-------------------------------------------------------------------------------
- SInt16 NextQDrive( void )
- {
- QHdrPtr qhdr = GetDrvQHdr(); // Pointer to Drive Queue
- DrvQEl *qel = (DrvQEl*) (qhdr->qHead); // Pointer to first element
- SInt16 drv = 8; // Start above built in drives
-
- while (qel) // While not end of queue,
- {
- if (qel->dQDrive == drv) // if drive number used,
- {
- drv++; // bump number, and
- qel = (DrvQEl*) (qhdr->qHead); // search from start
- }
- else // else next queue element
- qel = (DrvQEl*) (qel->qLink);
- }
-
- return(drv); // Return the next logical drive
- }
-
-
- //------------------------------------------------------------------------------
- // Function: FindMountedVol
- // Description: Searches the volume queue for a mounted volume specified
- // by vRefNum. If one is found, its VCB pointer is returned.
- //
- // Input: vRefNum: the volume reference to search for
- //
- // Output: the VCB pointer (NULL = volume not mounted)
- //-------------------------------------------------------------------------------
- static VCB *FindMountedVol(SInt16 vRefNum)
- {
- QHdrPtr volQ = GetVCBQHdr(); // VCB queue head pointer
- VCB *theVol = (volQ) ? (VCB*)volQ->qHead : 0; // first VCB
-
- while(theVol)
- {
- // The test for whether a volume is mounted or not is done using
- // the VCB fields vcbDrvNum and vcbDRefNum. A volume is mounted
- // only if it is online.
- //
- // online offline ejected
- //
- // vcbDrvNum >0 (DrvNum) 0 0
- // vcbDRefNum <0 (DRefNum) <0 (-DrvNum) >0 (DrvNum)
-
- if (theVol->vcbDrvNum == vRefNum) // if volume specified is online…
- break; // volume is mounted
-
- theVol = (VCB*)theVol->qLink; // next VCB
- }
-
- return(theVol);
- }
-
- //------------------------------------------------------------------------------
- // Function: MountedVolOfDrive
- //
- // Description: Searches the system VCB for a mounted volume on the specified
- // physical drive.
- //
- // Input: drive: pointer to the physical drive's record
- //
- // Output: the VCB pointer (nil if no volume mounted for drive)
- //-------------------------------------------------------------------------------
- VCB * MountedVolOfDrive(DriveRecPtr drive)
- {
- VolumeRecPtr vol = nil;
- VCB *vcb = nil;
-
- if (drive)
- {
- vol = drive->nextVol; // first volume (logical drive) of drive
- while (vol)
- {
- vcb = FindMountedVol(vol->vRefNum); // check if a volume is mounted
- if (vcb) // if mounted volume, stop now
- {
- break;
- }
- else // next volume of drive
- {
- vol = (VolumeRecPtr)vol->nextVol;
- }
- }
- }
-
- return(vcb);
- }
-
-
- //------------------------------------------------------------------------------
- // Function: UpdateQ
- // Description: Updates the specified drive in the system drive queue with
- // the specified capacity
- //
- // Input: qDrive: the drive to update
- // newSize: the new drive capacity
- //-------------------------------------------------------------------------------
- void UpdateQ(SInt16 qDrive, SInt32 newSize)
- {
- QHdrPtr qhdr = GetDrvQHdr(); // Pointer to Drive Queue
- DrvQEl *qel = (DrvQEl*) (qhdr->qHead); // Pointer to first element
-
- while (qel)
- {
- // Search until drive is found, then update its capacity
- if (qel->dQDrive == qDrive) // if drive number found,
- {
- qel->dQDrvSz2 = *(UInt16*)&newSize; // new capacity (hi word)
- qel->dQDrvSz = newSize; // low word of capacity
- break;
- }
- else // else next queue element
- qel = (DrvQEl*) (qel->qLink);
- }
- }
-
- //------------------------------------------------------------------------------
- // FUNCTION: NextPartitionID
- // PURPOSE: Returns the next unique partition ID for all volumes associated
- // with the specified drive. NOTE: This function should be used only
- // when adding volumes which do not have a partition map on the media.
- //
- // INPUT: drive: pointer to the drive record to search for next partition ID
- //
- // OUTPUT: a unique partition ID related to the specified volume
- //
- //-------------------------------------------------------------------------------
- SInt32 NextPartitionID(DriveRecPtr drive)
- {
- VolumeRecPtr vol = 0;
- SInt32 nextPartitionID = 1; // Start search with partition ID of 1
-
- if (drive) // if drive is present…
- {
- vol = (VolumeRecPtr)drive->nextVol; // first volume pointer
-
- while (vol) // while not end of volume queue…
- {
- if (vol->partitionNo == nextPartitionID) // if partition ID used
- {
- nextPartitionID++; // bump partition ID
- vol = drive->nextVol; // reset volume pointer
- }
- else
- vol = (VolumeRecPtr)vol->nextVol; // otherwise, point to next volume
- }
- }
-
- return(nextPartitionID); // nil if volume not found
- }
-
-
- //------------------------------------------------------------------------------
- // Function: MountVolumes
- // Description: Mounts all volume for the specified drive.
- //
- // Input: DriveRecPtr drive: drive with volumes to mount
- //
- // Output: Returns any errors that occur from PostEvent
- //-------------------------------------------------------------------------------
- OSErr MountVolumes( DriveRecPtr drive )
- {
- VolumeRecPtr vol;
- OSErr mountErr = noErr;
-
- // Post a Disk Inserted event for all HFS volumes not yet mounted
- if (drive) // for each drive…
- {
- vol = drive->nextVol; // first volume structure
- while (vol) // for all volumes on drive…
- {
- if ((vol->driveStatus.diskInPlace != 0) && // if media in place,
- (vol->mountthispart) && // and volume to be mounted,
- (!vol->partmounted)) // and hasn't been done yet
- {
- mountErr = PostEvent(diskEvt, vol->vRefNum);
-
- if ( mountErr == noErr )
- {
- vol->partmounted = true;
- }
- }
-
- vol = (VolumeRecPtr)vol->nextVol; // next per volume pointer
- }
- }
-
- return mountErr; // return error if one occurred
- }
-
-
- // This is to workaround a bug in the PowerPC native version of the AddDrive
- // call in systems before 8.5, where one needs to be added to the desired
- // drive number before calling AddDrive.
- // This function will check the system and pass the appropriate value to AddDrive
- void NativeAddDrive(SInt16 drvrRefNum, UInt16 driveNumber, DrvQElPtr drvQEl)
- {
- UInt32 gestaltResponse;
-
- // Check System version to see if we need to add one to AddDrive calls
- Gestalt (gestaltSystemVersion,(long *) &gestaltResponse);
- if( (gestaltResponse&0xFFFF) < 0x0850 )
- {
- // We are on a system before 8.5, we need to add 1 to AddDrive calls
- driveNumber += 1;
- }
-
- AddDrive( drvrRefNum, driveNumber, drvQEl);
- }
-
-