Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
RamDRVR.c
#define __DebugVersion 1 |
/* |
** Apple Macintosh Developer Technical Support |
** |
** RamDRVR.c: Driver for RamDisk Sample |
** |
** by Gordon Sheridan and Jim Luther |
** modified incessantly by Brian Bechtel |
** and even more so by Quinn "The Eskimo!" |
** |
** File: RamDRVR.c |
** |
** Copyright © 1992-1996 Apple Computer, Inc. |
** All rights reserved. |
** |
** You may incorporate this sample code into your applications without |
** restriction, though the sample code has been provided "AS IS" and the |
** responsibility for its operation is 100% yours. However, what you are |
** not permitted to do is to redistribute the source as "DTS Sample Code" |
** after having made changes. If you're going to re-distribute the source, |
** we require that you make it clear in the source that the code was |
** descended from Apple Sample Code, but that you've made changes. |
** |
** Change History (most recent first): |
** |
** <1.4> 19970207 Quinn Reworked to use new file layout and bring generally |
** up-to-date. |
** <1.3> 06/20/96 BL¡B Added DriverGestalt, no OLDROUTINENAMES |
** detailed comment on driveInfoCC call. |
** <6> 06/10/94 BL¡B Converted to work with Symantec as well. |
** <5> 05/19/94 BL¡B Converted to work with Metrowerks. Added |
** conditionally compiled main routine for Metrowerks. |
** <4> 10/23/93 JML Added check for valid globals before accepting |
** Prime, Control, or Status calls (except the control |
** and status routines that get and set the globals). |
** <3> 10/14/93 JML Added support for the following Control and Status |
** calls: physicalIconCC, mediaIconCC, driveInfoCC, |
** formatListSC. driveStatusSC now returns a copy |
** of our DrvQEl. Prime, Control and Status now checks |
** that ioVRefNum = our drive number. Prime now updates |
** dCtlPosition so I/O using fsFromMark will work. All |
** debugging code now hidden with "Panic" macros. Prime |
** now checks for block aligned I/O (since this is a |
** block device). All calls now return appropriate error |
** results. |
** <2+> 7/26/93 gs Set result = noErr for Status csCode = 8. |
** <2> 6/29/93 gs Return Drive Stats, miscellaneous clean up. |
** <1> 6/13/93 gs Allocate space for disk from driver. Clean up comments. |
** <0> 1/17/90 gs 11:58 PM, first version. |
**/ |
#ifdef __MWERKS__ |
#include <A4Stuff.h> |
#endif |
#ifdef THINK_C |
#include <SetupA4.h> |
#endif |
#include <DriverGestalt.h> |
#include <Disks.h> |
#include "RamDiskCommon.h" |
/////////////////////////////////////////////////////////////////////////// |
// These should be in <DriverGestalt.h>. |
enum { |
kdgFlush = 'flus' /* Determine if disk driver supports flush and if it needs a flush */ |
}; |
struct DriverGestaltFlushResponse { |
Boolean canFlush; /* Return true if driver supports the */ |
/* kdcFlush Driver Configure _Control call */ |
Boolean needsFlush; /* Return true if driver/device has data cached */ |
/* and needs to be flushed when the disk volume */ |
/* is flushed by the File Manager */ |
UInt8 pad[2]; |
}; |
typedef struct DriverGestaltFlushResponse DriverGestaltFlushResponse; |
enum { |
kdcFlush = 'flus' /* Tell a disk driver to flush its cache and any hardware caches */ |
}; |
#define GetDriverGestaltFlushResponse(p) ((DriverGestaltFlushResponse *)(&((p)->driverGestaltResponse))) |
/////////////////////////////////////////////////////////////////////////// |
// These definitely should be a system header file somewhere! |
enum { |
// Common control codes |
killIOCC = 1, /* kill I/O */ |
verifyDiskCC = 5, /* verify disk */ |
formatDiskCC = 6, /* format disk */ |
ejectDiskCC = 7, /* eject disk (ejectable media only) */ |
setTagBufferCC = 8, /* set tag buffer (.SONY) */ |
trackCacheCC = 9, /* control track cache (.SONY) */ |
physicalIconCC = 21, /* return physical location icon and where string */ |
mediaIconCC = 22, /* return media icon */ |
driveInfoCC = 23, /* return drive info */ |
trackDumpCC = 18244, /* diagnostic raw track dump (.SONY) */ |
// Common status codes |
returnFormatList = 6, /* return format list (.SONY) */ |
driveStatusSC = 8 /* drive status */ |
}; |
/////////////////////////////////////////////////////////////////////////// |
struct DriverConfigParam { |
QElemPtr qLink; |
short qType; |
short ioTrap; |
Ptr ioCmdAddr; |
ProcPtr ioCompletion; |
OSErr ioResult; |
StringPtr ioNamePtr; |
short ioVRefNum; |
short ioCRefNum; /* refNum for I/O operation */ |
short csCode; /* == kDriverConfigureCode */ |
OSType driverConfigureSelector; |
UInt32 driverConfigureParameter; |
}; |
typedef struct DriverConfigParam DriverConfigParam; |
/////////////////////////////////////////////////////////////////////////// |
// Prototypes for main driver entry points. |
extern pascal OSErr DRVROpen(ParmBlkPtr paramBlock, DCtlPtr devCtlEnt); |
extern pascal OSErr DRVRPrime(ParmBlkPtr paramBlock, DCtlPtr devCtlEnt); |
extern pascal OSErr DRVRControl(ParmBlkPtr paramBlock, DCtlPtr devCtlEnt); |
extern pascal OSErr DRVRStatus(ParmBlkPtr paramBlock, DCtlPtr devCtlEnt); |
extern pascal OSErr DRVRClose(ParmBlkPtr paramBlock, DCtlPtr devCtlEnt); |
/////////////////////////////////////////////////////////////////////////// |
pascal OSErr DRVROpen (ParmBlkPtr pb, DCtlPtr dce) |
{ |
DrvrGlobals *globe; |
OSErr result = noErr; |
#pragma unused (pb) |
if (!dce->dCtlStorage) /* is driver already open ? */ |
{ |
dce->dCtlStorage = (Handle)NewPtrSysClear(sizeof(DrvrGlobals)); |
if (!(Ptr)dce->dCtlStorage) |
{ |
result = MemError(); |
Panic("\pDRVROpen:NewPtr returned nil"); |
} |
globe = (DrvrGlobals *)dce->dCtlStorage; |
globe->driveNeedsFlush = false; |
} |
else |
Panic("\pDRVROpen:2nd open attempt"); |
return (result); |
} |
/*****************************************************************************/ |
pascal OSErr DRVRPrime (ParmBlkPtr pb, DCtlPtr dce) |
{ |
DrvrGlobals *globe; |
unsigned long position; |
unsigned long count; |
short calltype; |
OSErr result; |
if (dce->dCtlStorage) |
{ |
globe = (DrvrGlobals *)dce->dCtlStorage; |
if (globe->driveNumber != 0) /* accept no calls, before the globals are initialized */ |
{ |
position = dce->dCtlPosition; |
count = pb->ioParam.ioReqCount; |
/* Preflight the request for block alignment, size, and range */ |
if (((position % 512) == 0) && |
((count % 512) == 0) && |
((count + position) <= globe->ramSize)) |
{ |
calltype = 0x00FF & pb->ioParam.ioTrap; |
switch(calltype) |
{ |
case aRdCmd: |
/* Read the data */ |
BlockMoveData(&globe->ramDisk[position], pb->ioParam.ioBuffer, count); |
break; |
case aWrCmd: |
/* Write the data */ |
BlockMoveData(pb->ioParam.ioBuffer, &globe->ramDisk[position], count); |
globe->driveNeedsFlush = true; |
break; |
default: |
Panic("\pDRVRPrime: Call wasn't _Read or _Write"); |
break; |
} |
dce->dCtlPosition += count; /* Update the position */ |
pb->ioParam.ioActCount = count; /* Return the actual count */ |
result = noErr; |
} |
else |
{ |
Panic("\pDRVRPrime: Invalid block request"); |
result = paramErr; |
} |
} |
else |
{ |
Panic("\pDRVRPrime: Globals aren't initialized"); |
result = nsDrvErr; |
} |
} |
else |
{ |
Panic("\pDRVRPrime: No dCtlStorage"); |
result = notOpenErr; |
} |
return (result); |
} |
/*****************************************************************************/ |
pascal OSErr DRVRControl (ParmBlkPtr pb, DCtlPtr dce) |
{ |
DrvrGlobals *globe; |
OSErr result = controlErr; |
long size; |
long i; |
if (dce->dCtlStorage) |
{ |
globe = (DrvrGlobals *)dce->dCtlStorage; |
/* Accept only setGlobalsCC call, before the globals are initialized */ |
if (pb->cntrlParam.csCode == setGlobalsCC) |
{ |
/* Initialize DrvrGlobals */ |
BlockMoveData( *(Ptr *)pb->cntrlParam.csParam,(Ptr)globe, sizeof(DrvrGlobals)); |
result = noErr; |
} |
else if (globe->driveNumber != 0) |
{ |
switch(pb->cntrlParam.csCode) |
{ |
case killIOCC: |
/* What's there to kill? A BlockMove? sure... */ |
/* We call Panic in this example; a real driver */ |
/* would do something more reasonable. */ |
Panic("\pDRVRControl: KillIO on Ram Disk?"); |
break; |
case verifyDiskCC: |
result = noErr; |
break; |
case formatDiskCC: |
/* zero out ram disk memory */ |
size = globe->ramSize / 4; |
for (i = 0 ; i < size; i++) |
((long *)globe->ramDisk)[i] = 0; |
result = noErr; |
break; |
case ejectDiskCC: |
// From Martin Minow's SCSI disk sample: |
// Certain old SFGetFile calls (System 4.1?) will eject |
// disks which are marked as non-ejectable (such as this one) |
// If that happens, we need to issue a disk insert event |
// to remount the disk |
PostEvent(diskEvt, globe->driveNumber); |
break; |
case physicalIconCC: |
/* return pointer to icon and where string */ |
*(Ptr *)pb->cntrlParam.csParam = (Ptr)globe->physicalIcon; |
result = noErr; |
break; |
case mediaIconCC: |
/* return pointer to icon and where string */ |
*(Ptr *)pb->cntrlParam.csParam = (Ptr)globe->mediaIcon; |
result = noErr; |
break; |
// When a HFS volume is mounted, the File Manager calls the disk driver |
// with a "Return Drive Info" _Control call (csCode=23). Then if there |
// are no errors, it looks at the low-byte (bits 0-7) of csParam to see |
// if the drive type is ramDiskType (16, $10) or romDiskType (17, $11) |
// and if so, vcbAtDontCache is set in vcbAtrb. |
// |
// You shouldn't normally have to mess with the vcbAtDontCache bit in the |
// vcbAtrb. If you've written a RAM or ROM disk and you want the cache to |
// be bypassed, you only need to support _Control csCode 23 and say |
// you're a RAM or ROM disk. Other disk drivers probably should not mess |
// with the vcbAtDontCache bit because any improvements we make to the |
// File Manager cache will be lost on those drives (and we'll have to say |
// so when customers ask why our improvements didn't help their drives). |
// |
// See the Inside Macintosh:Files Errata technote for a discussion of this. |
case driveInfoCC: |
/* high word (bytes 2 & 3) clear */ |
/* byte 1 = primary + fixed media + internal */ |
/* byte 0 = drive type (0x10 = RAM disk) */ |
*(unsigned long *)pb->cntrlParam.csParam = 0x00000410; |
result = noErr; |
break; |
case 24: /* ¥¥¥ Return SCSI csCode Partition Size */ |
*(unsigned long *)pb->cntrlParam.csParam = globe->ramSize >> 9; |
result = noErr; |
break; |
case accRun: |
result = noErr; |
break; |
case kDriverConfigureCode: |
switch ( ((DriverConfigParam *)pb)->driverConfigureSelector ) |
{ |
case kdcFlush: |
globe->driveNeedsFlush = false; |
result = noErr; |
break; |
default: |
break; |
} |
break; |
default: |
Panic("\pUnrecognized control call"); |
break; |
} |
} |
else |
{ |
Panic("\pDRVRControl: Globals not initialized"); |
} |
} |
else |
{ |
Panic("\pDRVRControl: No dCtlStorage"); |
result = notOpenErr; |
} |
return (result); |
} |
/*****************************************************************************/ |
pascal OSErr DRVRStatus (ParmBlkPtr pb, DCtlPtr dce) |
{ |
DrvrGlobals *globe; |
OSErr result = statusErr; |
DrvSts *driveStats; |
DrvQElPtr driveQEl; |
DriverGestaltSyncResponse syncResponse; |
NumVersion versResponse; |
if (dce->dCtlStorage) |
{ |
globe = (DrvrGlobals *)dce->dCtlStorage; |
/* Accept only getGlobalsSC call, before the globals are initialized */ |
if (pb->cntrlParam.csCode == getGlobalsSC) |
{ |
*(long *)pb->cntrlParam.csParam = globe->ramSize; |
if (globe->ramSize == 0) |
{ |
Panic("\pDRVRStatus: ramSize is zero"); |
} |
result = noErr; |
} |
else if (globe->driveNumber != 0) |
{ |
switch(pb->cntrlParam.csCode) |
{ |
case driveStatusSC: |
if (pb->cntrlParam.ioVRefNum != globe->driveNumber) |
break; |
/* Drive Stats... */ |
driveStats = (DrvSts *)pb->cntrlParam.csParam; |
driveStats->track = 0; /* not applicable */ |
driveStats->writeProt = 0; /* write enabled */ |
driveStats->diskInPlace = 0x08; /* non-ejectable */ |
driveStats->installed = 1; /* drive installed */ |
driveStats->sides = 0; /* not applicable */ |
driveStats->twoSideFmt = 0; /* not applicable */ |
driveStats->needsFlush = 0; /* not applicable */ |
driveStats->diskErrs = 0; /* not applicable */ |
/* Copy qLink through dQFSID from our DrvQEl */ |
driveQEl = (DrvQElPtr)(GetDrvQHdr()->qHead); |
while(driveQEl != nil) |
{ |
if (driveQEl->dQDrive == globe->driveNumber) |
{ |
driveStats->qLink = driveQEl->qLink; |
driveStats->qType = driveQEl->qType; |
driveStats->dQDrive = driveQEl->dQDrive; |
driveStats->dQRefNum = driveQEl->dQRefNum; |
driveStats->dQFSID = driveQEl->dQFSID; |
break; /* while(driveQEl != nil) */ |
} |
driveQEl = (DrvQElPtr)(driveQEl->qLink); |
} |
result = noErr; |
break; |
case kDriverGestaltCode: |
/* We only support some information calls. A real driver */ |
/* would support more of these calls, as defined in the */ |
/* Designing PCI Cards & Drivers document */ |
switch ( ((DriverGestaltParam *)pb)->driverGestaltSelector ) |
{ |
case kdgSync: |
syncResponse.behavesSynchronously = true; |
((DriverGestaltParam *)pb)->driverGestaltResponse = |
*(unsigned long *)&syncResponse; |
result = noErr; |
break; |
case kdgFlush: |
{ |
GetDriverGestaltFlushResponse((DriverGestaltParam *)pb)->canFlush = true; |
GetDriverGestaltFlushResponse((DriverGestaltParam *)pb)->needsFlush = globe->driveNeedsFlush; |
result = noErr; |
} |
break; |
case kdgVersion: |
versResponse = globe->driverVersion; |
((DriverGestaltParam *)pb)->driverGestaltResponse = |
*(unsigned long *)&versResponse; |
result = noErr; |
break; |
default: |
break; |
} |
break; |
default: |
break; |
} |
} |
else |
{ |
Panic("\pDRVRStatus: Globals not initialized"); |
} |
} |
else |
{ |
Panic("\pDRVRStatus: No dCtlStorage"); |
result = notOpenErr; |
} |
return (result); |
} |
/*****************************************************************************/ |
pascal OSErr DRVRClose (ParmBlkPtr pb, DCtlPtr dce) |
{ |
DrvrGlobals *globe; |
#pragma unused (pb) |
if (dce->dCtlStorage) |
{ |
globe = (DrvrGlobals *)dce->dCtlStorage; |
if (globe->ramDisk) |
DisposePtr(globe->ramDisk); |
DisposePtr((Ptr)dce->dCtlStorage); |
} |
return (noErr); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14