home *** CD-ROM | disk | FTP | other *** search
- /*
- File: AsyncDriverMain.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.AsyncDriverSample" // <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
-
- }
-