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.
RAMDiskDriverMain.c
/* |
File: RAMDiskDriverMain.c |
Contains: Driver glue modified for use with CodeWarrior custom header. |
Written by: Quinn "The Eskimo!" |
Copyright: © 1996 by Apple Computer, Inc., all rights reserved. |
Change History (most recent first): |
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 "DSC 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): |
<5> 970307 Quinn Tidied up CodeWarrior driver header, |
as per Chad Magendanz's suggestions. |
<4> 970206 Quinn Ported to CodeWarrior, which required |
syntactic changes everywhere and some |
changes to how the entry point offsets |
are calculated. Also added A4 save, setup |
and restore. |
<3> 941027 BL¡B Incomplete async routines should return noErr . |
<2> 960803 BL¡B Moved to Universal Headers (post ETO 18). |
<1> 10/94 BL¡B Corrected asynch not-complete return case |
to put 0 in D0. |
<0> 10/93 gs and JML Clean up for Sample Code release. |
*/ |
#include <A4Stuff.h> |
#include <Devices.h> |
#include <DriverGestalt.h> |
/* This file is necessary because the standard Metrowerks driver header |
has a number of problems: |
o It assumes that the driver entry point is using C calling |
conventions. As you can't declare C calling convention routines |
in Pascal, I'm stuck with doing some sort of C glue. Given |
the other problems, I thought might as well do the whole enchilada. |
o It does not handle _KillIO processing. |
o It doesn't set ioResult for immediate calls. |
This code is based on the "Driver.a" used for the long standing |
DTS RAMDisk sample, modified for operation in the CodeWarrior |
environment. |
*/ |
// External declarations for the Pascal routines. |
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); |
// The Universal headers no longer define simple constants for low-memory |
// globals, so we have to define our own. |
enum { |
JIODone = 0x8FC |
}; |
// Constants for VMImmune bit in dCtlFlags. |
enum { |
dVMImmuneBit = 0, |
dVMImmuneMask = 0x0001 |
}; |
/* If dVMImmuneBit is set to true the VM system does not hold down |
parameter blocks (or the data that read/write parameter blocks point to) |
passed to this driver. |
*/ |
/* Driver Header |
The code is based on "Driver.a" from the RAMDisk sample. |
Unfortunately I had to make a number of changes. Some of them are purely |
syntactic, using 0x instead of $ for example, but others are more substantial. |
CodeWarrior's assembler doesn't let you go "dc.b Label1 - Label2", so |
the entry points in the driver header are now calculated using the label |
and a static offset. |
My second change was to save, setup and restore A4 in the code. |
*/ |
asm void __Startup__(void); |
asm void __Startup__(void) |
{ |
DHeader: |
DFlags: dc.w dReadEnableMask \ |
+ dWritEnableMask \ |
+ dCtlEnableMask \ |
+ dStatEnableMask \ |
+ dNeedLockMask \ |
+ dVMImmuneMask \ |
+ kmDriverGestaltEnableMask // <5> Driver flags |
DDelay: dc.w 0 // none |
DEMask: dc.w 0 // DA event mask |
DMenu: dc.w 0 // no menu |
dc.w DOpen + 8 // <4> <5> offset to Open |
dc.w DPrime + 10 // <4> <5> offset to Prime |
dc.w DControl + 12 // <4> <5> offset to Control |
dc.w DStatus + 14 // <4> <5> offset to Status |
dc.w DClose + 16 // <4> <5> offset to Close |
Name: dc.b "\p.RamDRVR" // <4> <5> name of driver |
DOpen: pea DRVROpen |
bra.s DRVRDispatch |
DPrime: pea DRVRPrime |
bra.s DRVRDispatch |
DControl: pea DRVRControl |
bra.s DRVRDispatch |
DStatus: pea DRVRStatus |
bra.s DRVRDispatch |
DClose: pea DRVRClose // and fall thru to DRVRDispatch |
DRVRDispatch: |
movem.l a0/a1/a4, -(sp) // <4> save registers (for IODone) |
// Push parameters for driver routines with Pascal calling conventions. |
clr.w -(sp) // save room for result |
move.l a0, -(sp) // push paramblock ptr on stack |
move.l a1, -(sp) // push dce ptr on stack |
// Now setup A4 -- have to do this after above because it messes up a0. |
jsr SetCurrentA4 // <4> establish CodeWarrior globals |
// Now call the driver routine. |
movea.l 0x16(sp), a0 // load address of driver routine into a0 |
jsr (a0) // go to it! |
move.w (sp)+, d0 // put result into d0 |
movem.l (sp)+, a0/a1/a4 // <4> restore registers (for IODone) |
addq.l #4, a7 // clear driver routine address off stack |
// Check for special case exits (Open, Close, KillIO, Immediate, incomplete Async) |
// Open, Close and KillIO always RTS to the Device Manager with the driver result |
// in |
move.w struct(IOParam.ioTrap)(a0), d1 // copy low byte of trap word to d1 |
// _Open check |
tst.b d1 // _Open == A000 |
beq.s Done // rts if _Open |
// _Close check |
cmpi.b #1, d1 // _Close == A001 |
beq.s Done // rts if _Close |
// _KillIO check |
cmpi.b #6, d1 // _KillIO == A006 |
beq.s Done // rts if _KillIO |
// It must be _Read, _Write, _Control, or _Status |
// Immediate check |
btst #noQueueBit, d1 // test immediate bit |
beq.s NotImmediate // branch if not immediate |
Immediate: |
move.w d0, struct(IOParam.ioResult)(a0) |
// The Device Manager doesn't set ioResult, |
// so we do just in case the caller checks |
// ioResult instead of the function result. |
bra.s Done // rts if immediate |
NotImmediate: |
// <3> BL¡B |
// If the call is asynchronous and not complete, it should return noErr (0) |
// in D0 instead of 1 -- otherwise, the Device Manager sees the 1 and |
// returns 1 as an error to the caller. If the File Manager is the caller, |
// it converts the 1 to ioErr and returns it to the program that called |
// it. See develop issue 13 page 10. |
// |
// Incomplete Async check |
cmp.w #1, d0 // We're using the convention that if the |
// driver result = 1 then the device driver |
// hasn't completed the non-immediate |
// operation. |
bne.s Complete |
moveq #0, d0 // clear D0 and... |
bra.s Done // rts if the operation is incomplete |
Complete: move.l JIODone, -(sp) // push jIODone onto stack |
Done: rts |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14