Refactor to use a single global reg

This commit is contained in:
Elliot Nunn 2021-04-04 08:00:34 +08:00
parent 6cd42fbc5f
commit da4e8b46c8
1 changed files with 213 additions and 225 deletions

View File

@ -4,6 +4,21 @@
****
***************************************************************************
; My global variables in a dCtlStorage handle
; The first $9C bytes are occupied by a window rec (of which grafPort is part)
rs.b $9C ; grafPort and windowRecord
gPB rs.l 1 ; keep PB&DCE together; both are pointers
gDCE rs.l 1
gGrafPortSave rs.l 1
gBackendRef rs.w 1
gBackendQHdr rs.l 1
gOpenBtn rs.l 1
gCloseBtn rs.l 1
gDiskBtn rs.l 1
gList rs.l 1
gSize rs.b 0
; "File entry" list (stored as a handle in dCtlStorage)
feQLink equ 0 ; long
feQType equ 4 ; word
@ -27,60 +42,132 @@ DAEntry ; See Device Manager IM:2
dc.w 0 ; No menu for this accessory
dc.w DAOpen-DAEntry ; Open routine
dc.w DADone-DAEntry ; Prime - unused
dc.w 0 ; Prime - unused
dc.w DACtl-DAEntry ; Control
dc.w DADone-DAEntry ; Status - unused
dc.w 0 ; Status - unused
dc.w DAClose-DAEntry ; Close
DATitle
dc.b 15, 'NetBoot Server', 0 ; DA Name (& Window Title)
dc.b 0, 0, $20, 1 ; traditional version
gBackendRefnum
dc.w 0
gBackendQHdr
dc.l 0
************************ DESK ACCESSORY GLUE ROUTINES ***********************
* These create a nice environment to do our actual work, described further down.
HackQueueHeader
dcb.b 10 ; our queue header for now...
* Some notes:
* The DeviceMgr does not require us to save any registers (no async routines).
* But it is a bit ambiguous about return values, so zero both IOResult and D0.
* Move A0/A1 to A2/A3 straight away so we can make calls that trash registers.
* "Open" returns its result via IOResult, all others via D0. Only Open can fail.
* "Control" returns via IODone (A1=DCE/D0=result), all others via RTS.
* We choose to save and set thePort for all routines. (We can't set it for Open
* because it doesn't exist, but we save thePort at the end as our dCtlWindow.)
* Limitation: no help with showing a menu
* I decided to keep our globals in a nonrelocatable block. Mac OS requires
* our window record to be in a fixed location, so we already pay the
* penalty of heap fragmentation. We might as well just make the window
* block a little bit bigger, and use the same register (A4) as the base of
* grafPort, windowRec AND globals.
************************ DESK ACCESSORY OPEN ROUTINE ***********************
DASetThePortAndA4 ; Leave A0 alone for the sake of DACtl
move.l $1E(A1),A4
movem.l A0/A1,gPB(A4)
move.l (A5),A1
move.l (A1),gGrafPortSave(A4)
move.l A4,(A1)
rts
DARestoreThePort
move.l (A5),A0
move.l gGrafPortSave(A4),(A0)
rts
DAOpen
movem.l A1-A4,-(SP) ; preserve A1-A4
move.l A1,A4 ; MOVE DCE pointer to a reg
clr.w $10(A0) ; TODO: don't always return noErr
move.l A0,-(SP) ; Allocate our global block...
move.l A1,-(SP)
move.l #gSize,D0
dc.w $A31E ; _NewPtrClear
move.l (SP)+,A1
move.l A0,$1E(A1) ; set dCtlWindow
move.l (SP)+,A0
bsr.s DASetThePortAndA4
bsr.s Init
bsr.s DARestoreThePort
rts
DAClose
bsr.s DASetThePortAndA4
bsr Teardown
bsr.s DARestoreThePort
move.l A4,A0 ; Deallocate our global block...
dc.w $A01F ; _DisposPtr
clr.w D0
rts
DACtl
movem.l $18(A0),D7/A0 ; D7=csCode A0=csParam(ie event ptr)
bsr.s DASetThePortAndA4 ; preserves A0 as a special favour
; Dispatch the control call...
cmp.w #64,D7 ; csCode == accEvent
bne.s .done
; tests for accRun, accCursor etc would go here
pea .done
cmp.w #1,(A0) ; check "what" field of event
beq MouseDownEvent
cmp.w #6,(A0)
beq UpdateEvent
rts
.done
bsr.s DARestoreThePort
move.l gDCE(A4),A1 ; return noErr
clr.w D0
move.l $8FC,A0 ; IODone
jmp (A0)
************************************************************************
* End of the header/glue. All below routines use registers as follows:
* D0: return value
* D1-D7: free to trash
* A0: pointer to event (if applicable)
* A1-A3: free to trash
* A4: our global pointer
* A5: app global pointer
* A6: probably shouldn't trash
************************************************************************
Init
; Install the backend driver (anywhere in the unit table)
move.w $18(A1),D0 ; dCtlRefNum, so we need A0 to be intact
not.w D0
asl.w #5,D0
or.w #$C000,D0 ; "owned resource" ID
if 0
subq #4,SP
move.l #'DRVR',-(SP)
bsr GetFirstOwnedResID
move.w D0,-(SP)
dc.w $A9A0 ; _GetResource (will be locked in sysheap)
move.l (SP)+,A0
move.l (A0),A0
bsr InstallAndOpenDriver
move.w D0,gBackendRef(A4)
; Create a fake queue to use until the backend driver is written
lea gBackendQHdr,A0
lea HackQueueHeader,A1
move.l A1,(A0)
sub #$32,SP
move.w D0,$18(SP) ; talk to backend driver
move.w #128,$1A(SP) ; get pointer to its linked list of disk images
move.l SP,A0
dc.w $A004 ; _Control
move.l $1C(SP),gBackendQHdr(A4)
add #$32,SP
endif
subq.l #4,SP ; FUNCTION = GrafPtr
move.l SP,-(SP) ; push a pointer to it
dc.w $A874 ; _GetPort ; push it on top of stack
tst.l $1E(A4) ; DCtlEntry.dCtlWindow do we have a window?
bne StdReturn ; If so, return, Else
******************************* NEW WINDOW ROUTINE *************************
move.l #156,D0 ; WindowRecord size
dc.w $A11E ; _NewPtr ; allocate space for record
; Create our window
subq #4,SP ; FUNCTION = WindowRef
move.l A0,-(SP) ; address of storage
move.l A4,-(SP) ; address of storage
pea theWindow ; boundsRect
pea DATitle ; title
clr.w -(SP) ; visible flag FALSE
@ -89,14 +176,14 @@ DAOpen
move.b #1,-(SP) ; goAway box TRUE
move.l #-1,-(SP) ; refCon = -1 (special)
dc.w $A913 ; __NewWindow
move.l (SP)+,A0
move.l A0,$1E(A4) ; DCtlEntry.DCtlWindow save windowPtr
move.w $18(A4),$6C(A0) ; DCtlEntry.DCtlRefNum system window
addq #4,SP
subq #4,SP ; Space for _NewControl results
move.l A0,D3
move.l gDCE(A4),A0
move.l $18(A0),$6C(A4) ; set windowKind to DCE.dCtlRefNum
move.l D3,-(SP) ; theWindow
; Add buttons to the window
subq #4,SP
move.l A4,-(SP) ; theWindow
pea OpenBtnRect ; boundsRect
pea OpenBtnTitle ; title
st -(SP) ; visible
@ -104,8 +191,10 @@ DAOpen
clr.l -(SP) ; max/procID=pushbtn
move.l #$80000000+OpenBtn-DAEntry,-(SP) ; refCon (high flag means pin right)
dc.w $A954 ; _NewControl
move.l (SP)+,gOpenBtn(A4)
move.l D3,-(SP) ; theWindow
subq #4,SP
move.l A4,-(SP) ; theWindow
pea CloseBtnRect ; boundsRect
pea CloseBtnTitle ; title
st -(SP) ; visible
@ -113,8 +202,10 @@ DAOpen
clr.l -(SP) ; max/procID=pushbtn
move.l #$80000000+CloseBtn-DAEntry,-(SP) ; refCon
dc.w $A954 ; _NewControl
move.l (SP)+,gCloseBtn(A4)
move.l D3,-(SP) ; theWindow
subq #4,SP
move.l A4,-(SP) ; theWindow
pea DiskBtnRect ; boundsRect
pea DiskBtnTitle ; title
st -(SP) ; visible
@ -122,167 +213,94 @@ DAOpen
clr.l -(SP) ; max/procID=pushbtn
move.l #DiskBtn-DAEntry,-(SP) ; refCon
dc.w $A954 ; _NewControl
move.l (SP)+,gDiskBtn(A4)
addq #4,SP ; no more _NewControl
; List Manager cares about the current port when created
subq #4,SP ; Save the GrafPort
move.l SP,-(SP)
dc.w $A874 ; _GetPort to the stack space we made
move.l $1E(A4),-(SP) ; dCtlWindow
dc.w $A873 ; _SetPort
; Use the cutesy small system font
subq #4,SP
pea theFontInputRecord
dc.w $A901 ; _FMSwapFont
addq #4,SP ; do we care at all?
; create the list
;; pascal ListHandle LNew(const Rect *rView, const ListBounds *dataBounds,
;Point cSize, short theProc, WindowRef theWindow, Boolean drawIt,
;Boolean hasGrow, Boolean scrollHoriz, Boolean scrollVert)
subq #4,SP
pea theList ; rView
pea listBounds ; dataBounds
clr.l -(SP) ; cSize
clr.w -(SP) ; theProc
move.l $1E(A4),-(SP) ; theWindow = dCtlWindow
move.l A4,-(SP) ; theWindow
st -(SP) ; drawIt
clr.w -(SP) ; hasGrow
clr.w -(SP) ; scrollHoriz
st -(SP) ; scrollVert
move.w #$44,-(SP)
dc.w $A9E7 ; _LNew
move.l (SP)+,gList(A4)
; Stuff the list handle in the window refcon, for want of a better place
move.l $1E(A4),A0
move.l (SP)+,$98(A0)
dc.w $A873 ; _SetPort restore
StdReturn
dc.w $A873 ; __SetPort ; old port on stack
movem.l (SP)+,A1-A4 ; restore regs
************************ DESK ACCESSORY DONE ROUTINE ***********************
DADone
moveq #0,D0 ; return no error
rts ; all done, exit
************************ DESK ACCESSORY CLOSE ROUTINE **********************
DAClose
movem.l A1-A4,-(SP) ; preserve A1-A4
move.l A1,A4 ; MOVE DCE ptr to A4
subq.l #4,SP ; FUNCTION = GrafPtr
move.l SP,-(SP) ; push a pointer to it
dc.w $A874 ; __GetPort ; get it, now it's on TOS
move.l $1E(A4),-(SP) ; DCtlEntry.DCtlWindow push the window
dc.w $A914 ; __DisposeWindow ; dispose of the window
clr.l 2(A3) ; DCtlEntry.DCtlWindow mark DCE properly
bra.s StdReturn ; all done with close, exit
********************** DESK ACCESSORY CONTROL ROUTINE **********************
DACtl
move.l A4,-(SP) ; preserve reg
move.l A1,A4 ; move DCE ptr to A4
move.w $1A(A0),D0 ; get the control opCode
sub.w #64,D0 ; = 64? (event)
beq.s DoCtlEvent
CtlDone
move.l A4,A1 ; put DCE ptr back in A1
move.l (SP)+,A4 ; restore reg
moveq #0,D0 ; return no error
move.l $8FC,-(SP) ; jump to IODone
clr.w D0
rts
Teardown
rts ; TODO write this!
************************** EVENT HANDLING ROUTINE **************************
DoCtlEvent
move.l A3,-(SP) ; save reg
move.l $1C(A0),A3 ; CntrlParam.CSParam = event pointer
move.w 0(A3),D0 ; EventRecord.what
cmp.w #1,D0
beq.s CtlEvtMouse
subq #6,D0 ; updateEvt is it an update?
bne.s CtlEvtDone ; If not, exit
UpdateEvent ; event pointer passed in A0, but not very interesting
move.l A4,-(SP) ; push grafPort
dc.w $A922 ; _BeginUpdate
move.l 2(A3),-(SP) ; EventRecord.message push windowPtr
dc.w $A922 ; __BeginUpdate ; begin the update operation
move.l $18(A4),-(SP) ; grafPort.visRgn
move.l gList(A4),-(SP) ; lHandle
move.w #$64,-(SP)
dc.w $A9E7 ; _LUpdate
move.l 2(A3),-(SP) ; EventRecord.message push windowPtr again
dc.w $A873 ; __SetPort
bsr DrawWindow ; draw our items
move.l A4,-(SP)
dc.w $A969 ; _DrawControls
move.l 2(A3),-(SP) ; EventRecord.message one more time
dc.w $A923 ; __EndUpdate ; end of update
bsr DrawFakeGrowBox
CtlEvtDone
move.l (SP)+,A3 ; restore reg
bra.s CtlDone ; exit
move.l A4,-(SP)
dc.w $A923 ; _EndUpdate
CtlEvtMouse
subq #4,SP ; Save the GrafPort (good manners)
move.l SP,-(SP)
dc.w $A874 ; _GetPort to the stack space we made
move.l $1E(A4),-(SP) ; dCtlWindow
dc.w $A873 ; _SetPort
rts
move.l 10(A3),-(SP); Get D4 as the point in our coords
MouseDownEvent ; event pointer passed in A0, very important
move.l A0,A2 ; A2 = event ptr
move.l 10(A2),-(SP) ; event.where
move.l SP,-(SP)
dc.w $A871 ; _GlobalToLocal
move.l (SP)+,D4
move.l (SP)+,D4 ; D4 = point in local coords
; Hit-test grow box
move.l D4,D0
bsr UseFakeGrowBox ; takes pt in D0, leaves old/new sizes in D0/D1
bne.s .didNotResize
bsr MoveWindowControls
bra.s .noControlClicked
bra.s .return
.didNotResize
subq #2,SP ; List Manager to handle it?
; Hit-test List Manager
subq #2,SP
move.l D4,-(SP)
move.w #1,2(SP) ; fake the X pos for _PtInRect to as "always yes"
move.l (A5),A0
move.l (A0),A0 ; the window record
move.l $98(A0),A2 ; the list handle
move.l (A2),-(SP) ; pointer to the first list field, namely the rect
move.l gList(A4),A0
move.l (A0),-(SP) ; pointer to the first list field, namely the rect
dc.w $A8AD ; _PtInRect
tst.b (SP)+
beq.s .notListClick
move.l D4,-(SP) ; pt
clr.w -(SP) ; modifiers
move.l A2,-(SP) ; lHandle
move.l gList(A4),-(SP) ; lHandle
move.w #24,-(SP)
dc.w $A9E7 ; _LClick
bra.s .noControlClicked
bra.s .return
.notListClick
; _FindControl to hit-test
; Hit-test controls
subq #4,SP ; room for the control handle
subq #2,SP ; return value (control ID)
move.l D4,-(SP) ; thePoint = our converted point
move.l $1E(A4),-(SP) ; theWindow = dCtlWindow
move.l A4,-(SP) ; theWindow
pea 10(SP) ; whichControl = pointer to where to dump handle
dc.w $A96C ; _FindControl
addq #2,SP ; don't care about ID
move.l (SP)+,D3 ; pop control handle
beq.s .noControlClicked
beq.s .return
; _TrackControl to hilite while mouse down
subq #2,SP ; room for result integer
@ -291,7 +309,7 @@ CtlEvtMouse
clr.l -(SP) ; actionProc = 0
dc.w $A968 ; _TrackControl
move.w (SP)+,D0
beq.s .noControlClicked
beq.s .return
move.l D3,A0 ; Use the low bits of rfCon as a routine offset
move.l (A0),A0
@ -300,34 +318,12 @@ CtlEvtMouse
add.w D0,A0
jsr (A0)
.noControlClicked
dc.w $A873 ; _SetPort to restore the GrafPort
bra CtlEvtDone
****************************** FONT METRICS *******************************
DrawWindow
move.l 2(A3),A0
move.l $18(A0),-(SP) ; get visRgn
move.l $98(A0),-(SP) ; cheeky, kept list handle in refcon
move.w #$64,-(SP)
dc.w $A9E7 ; _LUpdate
move.l 2(A3),-(SP)
dc.w $A969 ; _DrawControls
bsr DrawFakeGrowBox
Exit
rts
.return rts
***************************** SUBROUTINES ****************************
UseFakeGrowBox ; takes D0 as point argument, returns NE if not inside, old/new size in D0/D1
move.l (A5),A0
move.l (A0),A0
move.l $14(A0),D1
move.l $14(A4),D1 ; something about boundsRect?
sub.l D0,D1 ; always positive so should be fine?
cmp.w #16,D1
bgt.s .miss ; return NE
@ -337,30 +333,26 @@ UseFakeGrowBox ; takes D0 as point argument, returns NE if not inside, old/new s
; Hackity hack... use FakeWDEF to draw the resize-window outline
lea RealWDEFHandle,A1
move.l $7E(A0),(A1) ; save the real WDEF handle
move.l $7E(A4),(A1) ; save the real WDEF handle
lea FakeWDEF,A1
move.l A1,-(A1)
move.l A1,$7E(A0) ; insert the fake one
move.l A1,$7E(A4) ; insert the fake one
move.l $14(A0),-(SP) ; Keep botRight of old portRect
move.l $14(A4),-(SP) ; Keep botRight of old portRect
move.l A0,-(SP) ; _SizeWindow's theWindow
move.l A4,-(SP) ; _SizeWindow's theWindow
subq #4,SP ; _GrowWindow's return, _SizeWindow's w/h
move.l A0,-(SP) ; _GrowWindow's theWindow
move.l A4,-(SP) ; _GrowWindow's theWindow
move.l D0,-(SP) ; _GrowWindow's startPt
move.l SP,-(SP)
dc.w $A870 ; _LocalToGlobal on startPt
pea windowLimit
dc.w $A92B ; _GrowWindow
move.l (A5),A0
move.l (A0),A0
move.l RealWDEFHandle,$7E(A0) ; Undo the hack
move.l RealWDEFHandle,$7E(A4) ; Undo the hack
clr.w -(SP) ; _SizeWindow's fUpdate (do not touch update rgn)
dc.w $A91D ; _SizeWindow
move.l (A5),A0 ; return old/new size in D0/D1
move.l (A0),A0
move.l $14(A0),D1
move.l $14(A4),D1 ; return old/new size in D0/D1
clr.w D0 ; return EQ
movem.l (SP)+,D0 ; preserve D0 flag
.miss
@ -410,33 +402,33 @@ FakeWDEF
DrawFakeGrowBox ; fun little routine
kgbcnt equ 3
move.l (A5),A0
move.l (A0),A0
move.l $14(A0),-(SP) ; bottom/right of portRect
move.l D7,-(SP)
move.l $14(A4),-(SP) ; bottom/right of portRect
sub.l #$00080004,(SP)
dc.w $A893 ; _MoveTo
moveq.l #2-1,D4
moveq.l #2-1,D7
.loop
move.l #$0004FFFC,-(SP) ; lower left to upper right of stripe
dc.w $A892 ; _Line
move.l #$FFFA0002,-(SP) ; upper right of this to lower left of next
dc.w $A894 ; _Move
dbra D4,.loop
dbra D7,.loop
move.l (SP)+,D7
rts
MoveWindowControls ; takes old/new size in D0/D1
movem.l A2-A3/D3,-(SP)
bsr SubPt
move.l D1,D3 ; keep delta safe because we use it a lot
move.l (A5),A2
move.l (A2),A2 ; A2 is window
; Erase everything below the list
move.l $98(A2),A3 ; list handle as ever is in window refcon
move.l (A3),A0
move.l $14(A2),-(SP) ; botRight of window
move.l gList(A4),A0; list handle
move.l (A0),A0
move.l $14(A4),-(SP) ; botRight of window
clr.w -(SP) ; left of window
move.w 4(A0),-(SP) ; bottom of list
move.l SP,-(SP)
@ -444,18 +436,18 @@ MoveWindowControls ; takes old/new size in D0/D1
addq #8,SP
; Adjust the list
move.l $98(A2),A3 ; list handle as ever is in window refcon
move.l (A3),A0
move.l gList(A4),A2; list handle
move.l (A2),A0
move.l 4(A0),D1 ; current size field
move.l D3,D0 ; delta size
bsr AddPt
move.l D1,-(SP) ; listWidth/listHeight args to LSize
move.l A3,-(SP) ; lHandle
move.l A2,-(SP) ; lHandle
move.w #96,-(SP)
dc.w $A9E7 ; _LSize
; Move the buttons (what a pain!)
move.l $8C(A2),D0 ; handle to first control
move.l $8C(A4),D0 ; handle to first control
.ctlLoop
beq.s .doneControls
move.l D0,A3
@ -483,11 +475,12 @@ MoveWindowControls ; takes old/new size in D0/D1
bra.s .ctlLoop
.doneControls
move.l A2,-(SP)
move.l A4,-(SP)
dc.w $A969 ; _DrawControls
bsr DrawFakeGrowBox
movem.l (SP)+,A2-A3/D3
rts
@ -511,6 +504,20 @@ SubPt ; subtracts D0 from D1, preserving D0
rts
GetFirstOwnedResID
; Resources "owned" by this DA have an ID calculated from the DA's ID
; itself. But Font/DA Mover can change our ID from the default of 12, so
; we need to do this calculation at runtime. We determine our ID by
; converting our refNum to a unit number and therefore a resource ID.
; Return base ID of "owned resources" in D0
move.l gDCE(A4),A0
move.w $18(A0),D0
not.w D0
lsl.w #5,D0
or.w #$C000,D0
rts
***************************** CONTROLS ****************************
OpenBtnRect dc.w kWinH-20,kWinW-76,kWinH-3,kWinW-20
@ -564,9 +571,7 @@ OpenBtn
subq #2,SP
move.w #1,-(SP) ; one row
move.w #$7FFF,-(SP) ; beyond current bounds
move.l (A5),A0
move.l (A0),A0 ; window/grafport
move.l $98(A0),-(SP) ; lHandle = window refCon
move.l gList(A4),-(SP) ; lHandle
move.w #8,-(SP)
dc.w $A9E7 ; _LAddRow
move.w (SP)+,feListRow(A2)
@ -578,9 +583,7 @@ OpenBtn
move.w D0,-(SP) ; dataLen
move.w #0,-(SP) ; cell column
move.w feListRow(A2),-(SP) ; cell row
move.l (A5),A0
move.l (A0),A0 ; window/grafport handle
move.l $98(A0),-(SP) ; lHandle = window refCon
move.l gList(A4),-(SP) ; lHandle
move.w #88,-(SP)
dc.w $A9E7 ; _LSetCell
@ -594,9 +597,7 @@ CloseBtn
clr.w -(SP) ; result (boolean, so clear to be safe)
st -(SP) ; next (true means find next selected cell)
pea 4(SP) ; addr of some stack space to return row
move.l (A5),A0
move.l (A0),A0 ; window/grafport
move.l $98(A0),-(SP) ; lHandle = window refCon
move.l gList(A4),-(SP) ; lHandle
move.w #60,-(SP)
dc.w $A9E7 ; _LGetSelect
move.w (SP)+,D0
@ -635,9 +636,7 @@ CloseBtn
move.l SP,-(SP) ; rect ptr
swap D0
move.l D0,-(SP) ; cell
move.l (A5),A0
move.l (A0),A0 ; window/grafport
move.l $98(A0),-(SP) ; lHandle = window refCon
move.l gList(A4),-(SP) ; lHandle
move.w #76,-(SP)
dc.w $A9E7 ; _LRect
movem.l (SP)+,D0/D1 ; pop the result rect into registers
@ -658,9 +657,7 @@ CloseBtn
movem.l (SP)+,A0/D0
move.w #1,-(SP) ; count
move.w D0,-(SP) ; rowNum
move.l (A5),A0
move.l (A0),A0 ; window/grafport
move.l $98(A0),-(SP) ; lHandle = window refCon
move.l gList(A4),-(SP) ; lHandle
move.w #36,-(SP)
dc.w $A9E7 ; _LDelRow
@ -712,15 +709,6 @@ windowLimit DC.W kWinH,kWinW,32767,32767 ; minH,minW,maxH,maxW
theList DC.W 0,0,kWinH-24,kWinW-15 ; list top,left,bottom,right
listBounds DC.W 0,0,0,1
theFontInputRecord
dc.w 1 ; family
dc.w 0 ; size
dc.b 0 ; face/style
dc.b 1 ; needBits
dc.w 0 ; device
dc.w 1,1 ; scale numerator
dc.w 1,1 ; scale denominator
GetFile ; push a 74 byte SFReply structure to the stack
; push an SFReply structure
@ -790,7 +778,7 @@ InstallAndOpenDriver ; driver pointer is in A0, returns err code in D0
pea $12(A4) ; IOFileName = directly from the DRVR
move.l (SP)+,$12(A0)
dc.w $A000 ; _Open
move.w $10(A0),D0 ; return result
move.w $18(A0),D0 ; return IORefNum
add #$32,SP
movem.l (SP)+,A3-A4/D7