TweetFollow Us on Twitter

SCSI Driver
Volume Number:4
Issue Number:2
Column Tag:Forth Forum

A SCSI Driver in Forth

By Jörg Langowski, MacTutor Editorial Board, Grenoble, France

“An experimental SCSI driver in Mach2”

This column almost didn’t make it in time. Believe it or not, but while testing the SCSI driver of this article, my Quantum Q280 gave up. No, read on, it wasn’t the software. (How could it be MY software, anyway?) The interface board let go, and there was my most recent version of the driver, on the disk, inaccessible, me dummy having made no backup for the last 2 days. Left with ‘only’ a 20 MByte Seagate drive, I was going through a non-trivial exercise on how to debug a SCSI driver on the same disk which is used for developing it. You cannot imagine the strange things that can happen when booting from a disk with a partially functioning driver; it sometimes forces you into doing absolute no-nos such as booting from a floppy and attaching the SCSI connector afterwards so you can re-install the driver without getting la bombe immediately. At least, the development cycle is slowed down appreciably, since every other time you’ll have to boot from a floppy.

Anyway, here it is. The listing contains the Forth source of a SCSI driver which is more or less a translation of Apple’s assembly source into Mach2. It is quite long, and I’m not going through all of it in detail, having explained the function of most of the routines in my last column. One added feature is error retry; if a SCSI error happens, the offending command is repeated up to ten times.

The driver takes 50% more space than the assembly version and is about half as fast. So, you may ask, why go through all this trouble? You might have noticed the title ‘An experimental SCSI driver’. The code is meant for you to experiment with, add features - such as better error recognition and correction, multi- volume support, anything you may imagine. Or translate part of the routines into C or assembler. I just felt it was necessary to have a functioning example of a SCSI driver in some ‘higher-level’ language to make changes easier.

From the Forth point of view, I added a number of compiling words and glue routines that may be helpful for you in developing other things.

You already know the words :XDEF, ;XDEF, and XLEN from the Hypercard article. For easier programming of drivers and desk accessories, I now added :DA, ;DA, and DALEN which define the header of a driver, fill in the header after its definition is complete, and return the total length of the driver.

Since the SCSI driver code is jumped to at the beginning, it looks like other definition procedures from the outside, and its definition is therefore embedded between :XDEF and ;XDEF. In its interior, the SCSI driver contains a real DRVR, with is bracketed between :DA and ;DA. You recognize the glue code for the Open, Close, Control, Status and Prime routines at the end of the listing; the glue routines have been simplified by introducing macros for register save/restore and eventual jumps to the JIODone routine.

The Prime routine

Prime is the only one that has to be explained in more detail here since it has been modified with respect to the description given in the last issue. I added an error retry loop, and transfer of the SCSI data in variable size chunks. The code as printed takes 127 sectors on each read or write, that is, any amount of data larger than that will be transferred using several calls to the SCSICommon routine. This has been worked out empirically; larger transfer sizes would not work on the ST225N (which would result in files > 64K not being copied on a Finder copy). Your disk drive may allow larger sizes or need smaller ones; check this out if you like. You might also want to change the Read/Write Extended to a simple Read/Write command, or use a multi-transfer SCSI instruction block. The driver is certainly not generic and might need such adjustments to work on your disk.

SCSI Installation

The installation part has been changed slightly, and you’ll have to replace parts of the installer code given in the last column. First, I changed the device and partition maps such that the driver starts at block 4 and the Macintosh volume partition at block 16. This is where the Apple Hard Disk installation program seems to expect it, therefore you can easily replace this driver with the Apple driver in case of problems, without haveing to reformat the disk. Furthermore, I added a small routine that will install the driver code in the system heap and call it so that it gets installed in the unit table; this is an easy way of testing the driver without writing it to disk. You can even install the same disk that you are using to write the program, in which case you will be left with two drive icons on the desktop, referring to the same disk. For testing, this is OK, only don’t work too much in such an awkward configuration.

I hope this series of two articles has given you some ideas on how to write your own SCSI driver for your particular device. If someone comes up with a good examples for controlling a tape streamer - we’re always open for contributions, as you know.

Feedback Dept.

Someone read my complaints about the missing editor in Mach2; a letter with a disk arrived here recently:

“Dear Mr. Langowski,

I’m afraid I’m not a fan of Forth [Oh JL]. I like the idea of a stack-based language but there’s an impenetrable jargon barrier Besides, I just don’t like typing shifted characters, like #, !, % and so on. So I stay home with Pascal and Assembler.

On the other hand, I always at least glance at your column in MacTutor (as well as every other article that isn’t Mac II- specific). In the October issue, you say, ‘It is a shame that a powerful development system like Mach2 still lacks a reasonable integrated editor. At least multiple windows should be possible My standard development system is Mach2.13 with its editor and Mockwrite, plus Edit under Switcher if required.’ I’m stunned. The idea of using Mockwrite in a development system! The Mach2 editor must be really bad [ It’s not bad for what it does, i.e., has no major bugs; but I admit its features are limited - JL].

I had an editor problem myself, working with TML Pascal. TML won’t really run under the Switcher; it demands too much memory. So if I make a syntax error, I have to transfer to the editor, which means quitting the compiler and launching the editor, fix the error, then quit the editor and re-launch the compiler. Then I can re-compile. Something of a pain, particularly since error-free code is somewhat rare, at least when I’m the coder! [This sounds familiar. JL] My solution: Afterthought, a desk accessory programming editor. Now I fix bugs without leaving the compiler.

My problem is solved, and yours may be as well. I’m sending you a copy of Afterthought. It will open large files (up to 8 Megabytes), two at a time. It has most of the features of MDS Edit - the most significant exception is Replace All. And it’s reasonably fast. At the very least, it is better than Mockwrite!

Sincerely,

Clifford Story, Jimmy Mac Software, P.O.Box 957, Murfreesboro, Tennessee 37133.”

Thank you, Clifford, for developing a product that - I guess - many of our readers have been waiting for.

The disk contained the Afterthought desk accessory, its manual, some update notes and examples, a demo version, and a demo version of Idealiner, an idea processor written by the same author. The prices are, by the way, extremely reasonable; $20 for the editor and $40 for the idea processor. To find out more about these products, send mail to the above address, or GEnie mail to CLIFF.

The second editor desk accessory product that I find worth mentioning is JoliWrite, written by Benoît Widemann from Paris, a small (32K limit) text editor that is extremely useful for working with bulletin board services. Often, when you prepare a text off line for a BBS message, you wish to be able to enter the text free-format and then format into lines of so and so many characters, with paragraph indentation and justification if desired. Also, over here it is often necessary to convert accentuated characters from Macintosh into ASCII representation and back, and in general you might wish to be able to remove/add line feeds, clip off numbers from line starts, etc. JoliWrite does all that, and in addition is one of the few products that supports Undo on all operations. By the time you read this, an English translation of JoliWrite (shareware, 120F/US$20) will hopefully be available on the Macintosh section of GEnie.

Listing 1: An experimental SCSI driver
( © 1987 J. Langowski / MacTutor )
only forth definitions
also mac also assembler

CODE SCALE
    MOVE.L   (A6)+,D0
    BMI.S    @1
    MOVE.L   (A6),D1
    ASL.L    D0,D1
    MOVE.L   D1,(A6)
    RTS
@1  MOVE.L   (A6),D1
    NEG.L    D0
    ASR.L    D0,D1
    MOVE.L   D1,(A6)
    RTS
END-CODE

: 4ASCII 0
 4 0 DO 
 8 SCALE 0 WORD 1+ C@ + LOOP
;

( *** compiler support words for external definitions *** )
: :xdef 
 create -4 allot
 $4EFA w, ( JMP )
 0 w,  ( entry point to be filled later )
 0 ,   ( length of routine to be filled later )
 here 6 - 76543
;

: ;xdef { branch marker entry | -- }
 marker 76543 <> abort” xdef mismatch”
 entry branch - branch w!
 here branch - 2+ branch 2+ !
; 
 
: xlen 4 + @ ; ( get length word of external definition )

( *** driver header block *** )

 0 CONSTANT drvrFlags
 2 CONSTANT drvrdelay 
 4 CONSTANT drvrEMask
 6 CONSTANT drvrMenu
 8 CONSTANT drvrOpen
10 CONSTANT drvrPrime
12 CONSTANT drvrCtl
14 CONSTANT drvrStatus
16 CONSTANT drvrClose
18 CONSTANT drvrname
50 CONSTANT DAlength

( *** compiler support words for DA and driver definitions *** )
: :DA 
 create -4 allot
 here 87654 ( start of DA block, and marker )
 54 allot   ( length of block )
;

: ;DA { DAstart marker Ropen Rprime Rctl Rstatus Rclose
 Rflags Rdelay Remask Rmenu Rname | -- }
 marker 87654 <> abort” DA definition mismatch”
 Ropen  DAStart - DAStart drvrOpen + w!
 Rprime DAStart - DAStart drvrPrime + w!
 Rctl   DAStart - DAStart drvrCtl + w!
 Rstatus  DAStart - DAStart drvrStatus + w!
 Rclose DAStart - DAStart drvrClose + w!
 Rflags DAStart drvrFlags + w!
 Rdelay DAStart drvrDelay + w!
 Remask DAStart drvrEmask + w!
 RMenu  DAStart drvrMenu + w!
 Rname count dup   DAStart drvrName + c!
 DAStart drvrName + 1+ swap 
 dup 31 > if drop 31 then cmove 
 here DAstart -  DAStart DAlength + !
; 
 
: DAlen DAlength + @ ; ( get length word of external definition )

\ ------------------------------------------------------
\ some macros needed in the driver
\ ------------------------------------------------------

CODE xchg ( exchange word halves on top of stack )
 move.l (a6)+,d1
 swap.w d1
 move.l d1,-(a6)
 rts
END-CODE MACH
 
CODE min
 MOVE.L    (A6)+,D0                            
 CMP.L     (A6),D0                             
 BGE.S     @1        
 MOVE.L    D0,(A6)                             
@1 RTS 
END-CODE MACH

CODE shl ( data #bits )
 MOVE.L (A6)+,D0
 MOVE.L (A6),D1
 LSL.L  D0,D1
 MOVE.L D1,(A6)
 RTS
END-CODEMACH

CODE shr ( data #bits )
 MOVE.L (A6)+,D0
 MOVE.L (A6),D1
 LSR.L  D0,D1
 MOVE.L D1,(A6)
 RTS
END-CODEMACH

CODE w*
 MOVE.L (A6)+,D1
 MOVE.L (A6)+,D0
 MULS.W D1,D0
 MOVE.L D0,-(A6)
 RTS
END-CODE MACH

\ ------------------------------------------------------
\ **** DA glue macros
\ ------------------------------------------------------

$8FC CONSTANT JioDone 

CODE DA.prelude
 LINK A6,#-512   ( 512 bytes of local Forth stack )
 MOVEM.L A0-A1,-(A7) ( save registers )
 MOVE.L  A6,A3   ( setup local loop return stack )
 SUBA.L  #256,A3 ( in the low 256 local stack bytes )
 MOVE.L  A0,-(A6)  ( parameter block )
 MOVE.L  A1,-(A6)( device control entry )
 RTS    \ just to indicate the MACHro stops here 
END-CODE MACH

CODE DA.epilogue
 MOVE.L  (A6)+,D0( return code )
 MOVEM.L (A7)+,A0-A1 ( restore registers )
 UNLK A6
 RTS
END-CODE MACH

CODE DA.JIODone
 MOVE.L  (A6)+,D0( return code )
 MOVEM.L (A7)+,A0-A1 ( restore registers )
 UNLK A6
 move.l JIODone,A0
 movem.l d4-d7/a4-a6,-(a7)
 jsr    (a0)
 movem.l(a7)+,d4-d7/a4-a6
 RTS
END-CODE MACH

.trap _newptr,sys,clr$A71E

\ fields of device control entry
 4 CONSTANT dCtlFlags
 6 CONSTANT dCtlQHdr
16 CONSTANT dCtlPosition
20 CONSTANT dCtlStorage
24 CONSTANT dCtlRefNum
26 CONSTANT dCtlCurTicks
30 CONSTANT dCtlWindow
34 CONSTANT dCtlDelay
36 CONSTANT dCtlEMask
38 CONSTANT dCtlMenu

\ parameter block constants

0   CONSTANT  qLink\ ptr to next queue entry[long word]
4   CONSTANT  qType\ queue type [word]
6   CONSTANT  ioTrap \ routine trap [word]
7   CONSTANT  ioTrap+1    \ read or write command
8   CONSTANT  ioCmdAddr \ routine address [long word]
12  CONSTANT  ioCompletion\ addr of completion routine
16  CONSTANT  ioResult    \ result code returned here
18  CONSTANT  ioNamePtr \ pointer to file name string
22  CONSTANT  ioVRefNum \ volume reference number
26  CONSTANT  csCode ( type of control call )
28  CONSTANT  csParam( control call parameters )

\ MFS I/O Parameter Block
24 CONSTANT ioRefNum
26 CONSTANT ioVersNum
27 CONSTANT ioPermssn
28 CONSTANT ioMisc
32 CONSTANT ioBuffer
36 CONSTANT ioReqCount
40 CONSTANT ioActCount
44 CONSTANT ioPosMode
46 CONSTANT ioPosOffset
50 CONSTANT IOParamBlkSize

4ascii SDRV constant “sdrv
4ascii TFS1 constant “tfs1

\ Equates
\ My excuses for the format. This has been taken almost
\ ‘as is’ from Apple’s SCSI driver example. - jl -

EQUverChar$34  \ version ‘4’
EQUSCSIZE 10   \ size of SCSI extended command
 
\ Equates for our storage (pointed to by DCtlStorage)
EQUOffset 0   \ [long] offset of starting sector
EQUMyDQEl Offset+4   
\ [20 bytes] drive queue element (with flags) for this drive
EQUMyDrvNum MyDQEl+20       
 \ [word] drive num (determined by scanning drive queue)
EQUNextAddr MyDrvNum+2      
 \ [long] ptr to current block buffer
EQUTickleFlag  NextAddr+4      
 \ [byte] Do we need to remind the system about this drive?
EQUBlindOKTickleFlag+1    
 \ [byte] Can we use blind reads?
 \ I left this in to keep the format the same. 
 \ We don’t need it since our driver does not read blind. 
EQUSCmd BlindOK+1       
 \ [10 bytes] SCSI extended cmd Block /JL
EQUStatWord SCmd+10         \
  [word] status and message bytes...
EQUMsgWordStatWord+2      
 \ [word] ... returned by SCSIComplete

EQUOurIDMsgWord+2  \ [word] our SCSI ID
EQUSCSIPseudo  OurID+2         
 \ [30 bytes] SCSI pseudo-code program 
 \ - three instructions long
EQUSCSIPar1 SCSIPseudo+2  \ first SCSI code paramr (long)
EQUSCSIPar2 SCSIPar1+4  \ 2nd SCSI code parameter (long)
EQUDiskVarLth  SCSIPseudo+(SCSIZE*3) 
 \ length of our locals . . .
EQU DQDrvSize  12
 
EQU realSizeMyDQEl+DQDrvSize+4

\ equates for CSParam offsets for our special control call
EQUDSCCmd CSParam
 \ Ptr to SCSI command block
EQUDSCPseudoDSCCmd+4 \ Ptr to SCSI pseudocode (if any          
 bytes to xfer)
EQUDSCBufferDSCPseudo+4 \ Ptr to buffer for transfer (if       
 any)
EQUDSCSizeDSCBuffer+4\ Size of transfer, signed (+ if          
 read, - if write)
EQUDSCTicks DSCSize+4\ Tick count we’re willing to wait        
 for completion
EQUDSCCmdSize  DSCTicks+4 \ (word) Size of command block we’re 
 sending (usually 6)
 
EQU   KillCode 1 
EQUVerifyCode  5
EQUFormatCode  6
EQUEjectCode7
EQUIconCode 21
EQU   AccRun65
EQUSCSICode 77      
 \ our own special code (defined above)
 
EQUControlErr  -1
EQUStatusErr-1
EQUParamErr -50
EQUnsDrvErr -56
EQUnsVErr -35
EQUioErr-36

EQUdNeedTime$DFFF
 \ to clear bit 5 of high byte in drvrFlags

EQUDiskInsertEvt 7
EQU   SysEvtMask $144
EQU   UTableBase $11C
EQU   DrvQHdr    $308
EQU   QHead $2

EQUDQDrive6
EQUDQRefNum 8
EQUDQFSid 10

EQUPDSig0
EQUPDSigWord$5453
EQUPDFSID 8
EQUPDLen12

\ ______________________________________________
\ The code starts here.
\ ______________________________________________
:XDEF ScsiDisk  
 \ compiles a jump to the install code at the end 
 \ which will be resolved at the end of the definition.
:DADiskDrvr  
 \ this word provides the driver header structure
        .ALIGN
\ Q200 Icon, as given by Quantum
\ If you find this ‘snail’ ugly, feel free to change it ...
\  J.L.
header  SCSIIcon        
DC.L $00000000   DC.L $00000000 
DC.L $00000000   DC.L $000FF000        
DC.L $003FFC00   DC.L $00FFFF00 
DC.L $01FFFF80   DC.L $03F81FC0        
DC.L $07E007E0   DC.L $07C003E0 
DC.L $0F8001F0   DC.L $0F0000F0 
DC.L $1F0000F8   DC.L $1E000078 
DC.L $1E000078   DC.L $1E000078 
DC.L $1E000078   DC.L $1E000078 
DC.L $1E000078   DC.L $1F0000F8
DC.L $0F0000F0   DC.L $0F8001F0 
DC.L $07C003E0   DC.L $07E007E0
DC.L $03F80000   DC.L $01FFFFF0 
DC.L $00FFFFF8   DC.L $003FFFF8
DC.L $000FFFF8   DC.L $00000000 
DC.L $00000000   DC.L $00000000

DC.L $00000000   DC.L $00000000 
DC.L $000FF000   DC.L $003FFC00
DC.L $00FFFF00   DC.L $01FFFF80 
DC.L $03FFFFC0   DC.L $07FFFFE0
DC.L $0FFFFFF0   DC.L $0FFFFFF0 
DC.L $1FFFFFF8   DC.L $1FFFFFF8
DC.L $3FFFFFFC   DC.L $3FFFFFFC 
DC.L $3FFFFFFC   DC.L $3FFFFFFC
DC.L $3FFFFFFC   DC.L $3FFFFFFC 
DC.L $3FFFFFFC   DC.L $3FFFFFFC
DC.L $1FFFFFF8   DC.L $1FFFFFF8 
DC.L $0FFFFFF0   DC.L $0FFFFFF0
DC.L $07FFFFF0   DC.L $03FFFFF8 
DC.L $01FFFFFC   DC.L $00FFFFFC
DC.L $003FFFFC   DC.L $000FFFFC 
DC.L $00000000   DC.L $00000000
 
\ Our “Where:” string
        DC.B    11
        DC.B    ‘Q200 (SCSI)’
        .ALIGN
\ SCSI handler glue routines
CODE SCSIReset ( -- result code )
 CLR.W -(A7)
 MOVE.W #0,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSIGet ( -- result code )
 CLR.W -(A7)
 MOVE.W #1,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSISelect ( TargetID -- SCSIErrorResult )
 MOVE.L (A6)+,D0
 CLR.W -(A7)
 MOVE.W D0,-(A7)
 MOVE.W #2,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSICmd ( buffer count -- SCSIErrorResult )
 MOVE.L (A6)+,D0
 MOVE.L (A6)+,D1
 CLR.W -(A7)
 MOVE.L D1,-(A7)
 MOVE.W D0,-(A7)
 MOVE.W #3,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSIComplete ( waitTicks mess stat -- SCSIErrorResult )
 CLR.W -(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.W #4,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

1 CONSTANT SCInc 2 CONSTANT SCnoInc
3 CONSTANT SCAdd 4 CONSTANT SCMove
5 CONSTANT SCLoop6 CONSTANT SCNop
7 CONSTANT SCStop8 CONSTANT SCComp

\ ----------------------------------------------------
\ main driver routines start here
\ ----------------------------------------------------

: SCSICommon 
 \ written to emulate the SCSICommon 
 \ routine in Apple’s example 
 \ as closely as possible.
 { pseudo cmdblock ourVars ticks bytes cmdsize 
 | writing mess stat -- result }

 SCSIGet 0= IF
 ourVars ourID + w@ 
 SCSISelect 0= IF
 cmdBlock cmdSize SCSICmd 0= bytes AND IF
 pseudo bytes 0< \ bytes <0 if writing
 IF (call) SCSIWrite drop
 ELSE (call) SCSIRead drop THEN
\ Note: Your system may be able to support blind transfers.
\ Here is the place to experiment with such things --
 THEN
 ticks ^ mess ^ stat SCSIComplete
 0= IF  
 stat $FF AND IF ioErr 
 ( there was an SCSI error )
 ELSE 0 ( successful completion ) THEN
 ELSE ( complete unsuccessful ) ioErr
 THEN
 ELSE ( select unsuccessful ) ioErr
 THEN
 ELSE ( get unsuccessful ) ioErr
 THEN
;

: DiskClose { parblk dce | -- result }
 0 ( result code = OK ) ;

: diskControl { parblk dce | ourVars -- result }
 dce DCtlStorage + @ -> ourVars    
 parblk csCode + w@
 CASE
 killCode OF0 ENDOF
 verifyCode OF 0 ENDOF
 formatCode OF 0 ENDOF

 ejectCodeOF
 ourVars MyDrvNum + w@ 
 \ check drive # in request
 parblk  IOVRefNum + w@ =  \ the same?
 IF
 SysEvtMask w@ IF ( we’re not at boot time )
 DiskInsertEvt
 MyDrvNum ourVars + w@
 (call) PostEvent drop
 ELSE ( boot time )
 1 ourVars tickleFlag + c!
 ( drive will be remembered after boot )
 THEN
 controlErr
 ELSE nsDrvErr
 THEN
 ENDOF

 iconCode OF [‘] SCSIIcon parblk csParam + ! 
 0 ENDOF

 accRun OF
 ourVars tickleFlag + c@ 
 ourVars offset + @ 0= not 
 ( we have a good partition )
 AND
 IF 
 DiskInsertEvt
 MyDrvNum ourVars + w@
 (call) PostEvent drop
 THEN
 0 dce DCtlDelay + w!
 dce DCtlFlags + dup w@ 
 dNeedTime AND swap w! ( clear flag )
 0 ourVars tickleFlag + c!
 0 ENDOF

 scsiCode OF
 parblk dup DSCPseudo + @
 dup DSCCmd + @
 ourVars
 dup DSCTicks + @
 dup DSCSize + @
 DSCCmdSize + w@
 SCSICommon
 ENDOF

 ( otherwise ) 
 controlErr
 ENDCASE
;
 
: DiskStatus { parblk dce | -- result } statusErr ;

CODE GetSysPtr
 move.l (a6)+,d0
 _newptr,sys,clr
 move.l a0,-(a6)
 rts
END-CODE

CODE AddDrv ( dqe refnum drv# | -- )
 move.l (a6)+,d0
 move.l (a6)+,d1
 swap.w d0
 move.w d1,d0
 move.l (a6)+,a0
 _AddDrive
 rts
END-CODE
 
: DiskOpen { parblk dce | 
 ourVars thisQElem driveNum dqe SCSIprog -- result }

 DiskVarLth GetSysPtr dup 
 \ get memory for local variables 
 -> ourVars dce DCtlStorage + !  
 \ and store pointer to it
 100 5 DO \ find unused drive #
 DrvQHdr QHead + @ -> thisQElem  \ scan queue
 BEGIN thisQElem 0= IF i leave THEN
 \ end of queue? we have a good number
 thisQElem DQDrive + w@
 i <> WHILE
 \ keep scanning as long as # is not in use
 thisQElem ( QLink + ) @ -> thisQElem
 REPEAT
 LOOP -> driveNum
 driveNum ourVars myDrvNum + w! 
 \ remember drive # in local vars
\ ( following text taken from Apple’s generic driver )
\ Add a drive to the drive queue. First, some fun facts:
\ The drive queue element starts four bytes before the DQEPtr!
\ These four bytes contain “hardware-locked”, “ejectable”, and
\ “disk-in-place” info.
\ 
\ Not As Interesting But Still True: HFS supports volumes 
\ >32MBytes, but since the dqDrvSize field in the DQE is only 
\ a word, the Software Gurus had to resort to bizarre sorcery:
\ If the qType field (formerly unused in DQE’s) is 1, the word
\ following the dqDriveSize field is assumed to be the high-order
\ word of a LongInt block count! (dqDriveSize is still the low-
\ order word). It works even if the size doesn’t require both 
\ words, so we always do it this way.
\
\ See: Tech Note #36.
 
 ourVars MyDQEl + 8 over w! 
 \ set non-ejectable and clear the rest
 2+ 0 over w! 2+  -> dqe  
 \ this is the real start of the DQElem
 1 dqe qType + w!\ large vol queue type
 0 dqe dqDrvSize + ! \ no size yet
 0 dqe dQFSID + w! \ normal file system
 dqe 
 dce DCtlRefNum + w@ 
 driveNum AddDrv \ add drive to queue
 
 \ now set up SCSI pseudo program in driver’s local vars

 ourVars SCSIPseudo +  -> SCSIprog
 scnoinc SCSIprog w!
 scstop  SCSIprog scsize + w!
 0 \ result code = good
;

: DiskPrime { parblk dce | 
 ourVars sectors bytes start size r/w sect transferred error
  -- result } 

 dce dCtlStorage + @ -> ourVars  \ setup local var pointer
 1 ourVars TickleFlag + c!

 \ convert byte count into number of sectors
 parblk IOReqCount + @ 9 shr $1FFFFF AND -> sectors
 \ convert starting position into sector number
 dce dCtlPosition + @ 9 shr $1FFFFF AND -> start
 
 ourVars realSize + @ xchg -> size \ get drive size
 start sectors + size 1+ < IF ( valid request )
 0 -> transferred
 ourVars ( offset + ) @ +> start 
 \ offset by start of partition

 parBlk IOTrap+1 + c@ 3 = ( is this a write command? )
 IF  -1 -> r/w $2A00 ( SCSI extended write )
 ELSE 1 -> r/w $2800 ( SCSI extended read ) 
 THEN
 ourVars SCmd + w! \ put the command away 

 BEGIN ( transfer loop )

\ If you have problems getting the SCSI transfer to work
\ with your particular disk, try changing the number of
\ sectors transferred on each call ( 127 here )
\ or change the read/write extended to a normal read/write.
 \ Note that in that case you’ll have to change the command 
 \ block setup as well. 

 127 sectors min -> sect
 transferred +> start
 parblk IOBuffer + @ transferred 9 shl + 
 ourVars SCSIPar1 + ! 
 sect 9 shl dup -> bytes 
 ourVars SCSIPar2 + !  \ set # of bytes

 start ourVars SCmd + 2+ !
 \ set starting position in command block
 bytes 2/ ourVars SCmd + 6 + !  \ set # of sectors
 
 IOErr ( preset, if loop with retry is unsuccessful )
 10 0 DO ( retry max 10 times )
 ourVars SCSIPseudo +
 ourVars SCmd +
 ourVars 60 r/w 10
 SCSICommon 0= IF drop 0 leave THEN
 1 (call) sysbeep \ just for debugging, 
 \ beeps if SCSI did not complete successfully
 LOOP -> error
 -127 +> sectors
 sectors 1- 0< 
 UNTIL ( transfer loop )
 error dup 0= IF
 parBlk IOReqCount + @ -> bytes
 bytes parBlk IOActCount + ! 
 \ we transferred the # of bytes requested
 bytes dce DCtlPosition + +!
 THEN
 ELSE IOErr
 THEN   
;

CODE DrvrInst ( unitNum | -- )
 move.l (a6)+,d0
 not.w  d0
 _DrvrInstall
 rts
END-CODE
 
CODE DrvrRem ( unitNum | -- )
 move.l (a6)+,d0
 not.w  d0
 _DrvrRemove
 rts
END-CODE

CODE openMe ( drvrName | result -- )
 \ allocates a parameter block on the A7 stack and calls
 \ the _open trap. This is easier to do in assembly --
 moveq.l#(IOParamBlkSize/2)-1,d0
@1 clr.w-(a7)
 dbra d0,@1
 move.l a7,a0
 move.l (a6)+,IONamePtr(a0)
 _Open
 add.w  #IOParamBlkSize,a7
 move.l d0,-(a6)
 rts
END-CODE

: RealInstall 
\ This routine is called by the system boot code with 
\ the SCSI ID of the disk in D5 and a pointer to its
\ partition map in A0. We therefore need some special glue code. 
\ Note that Mach2 allows to do the stack parameter / local
\ variable declaration after this glue code without any problems
 LINK A6,#-512   ( 512 bytes of local Forth stack )
 MOVEM.L A2-A6/D2-D7,-(A7)( save registers )
 MOVE.L  A6,A3   ( setup local loop return stack )
 SUBA.L  #256,A3 ( in the low 256 local stack bytes )
 MOVE.L  A0,-(A6)  ( partition table pointer )
 MOVE.L  D5,-(A6)( SCSI ID )
 
 { partition ID | unitNum hdce dce ourVars pt -- }

 ID 32 + -> unitNum
 unitNum DrvrInst\ allocate DCE and install it
 unitNum 4 w* UTableBase @ + @ -> hdce \ dce handle
 hdce @ -> dce \ get dce pointer
 [‘] DiskDrvr dce ( DCtlDriver + ) ! 
 \ put pointer to driver into dce  
 [‘] DiskDrvr drvrFlags + w@
 dce DCtlFlags + w!
 \ move driver flags, RAMbase should be cleared
 0 dce DCtlDelay + w!\ no time needed yet
 [‘] DiskDrvr drvrEMask + @
 dce DCtlEMask + ! \ move event mask and menu

 [‘] DiskDrvr drvrName + openMe  \ try to open this driver
 IF ( not OK ) unitNum DrvrRem
    [‘] Scsidisk (call) DisposPtr
    bra @1 \ exit hack. 
 \ This is the Mach2 equivalent of the 
 \ Ugly Goto Statement in Pascal. 
 \ Sorry, but it is so much easier this way...
 THEN 
 
 hdce @ -> dce 
 \ deref this handle again, may have changed
 dce dCtlStorage + @ -> ourVars
 ID ourVars ourID + w!
 partition IF 
 \ well, we should have a non-NIL partition at least...
 partition ( PDSig + ) w@ PDSigWord = IF
 \ and it should be a Macintosh one. The NEW Apple drivers
 \ have a different sig word and DPM format that you 
 \ might want to take into account here (see text). 
 partition 2+ -> pt
 BEGIN
 pt PDFSID + @ ?dup WHILE 
 \ otherwise no good partition found
 “tfs1 = 
 IF ( correct file system ID )
 pt @ ourVars Offset + !
 pt 4 + @ xchg 
 ( long drive size, hi word <-> lo word )
 ourVars realSize + !
 SysEvtMask w@ 0= IF \ we’re booting
 dce dCtlFlags + dup w@ 
 $2000 OR swap w!
 ( set dNeedTime flag )
 1 dce dCtlDelay + w!
 1 ourVars TickleFlag + c!
 THEN 
 THEN
 12 +> pt
 REPEAT
 THEN THEN
 
@1 UNLK A2\ which was used for local variables
 MOVEM.L (A7)+,A2-A6/D2-D7( restore registers )
 UNLK A6
 RTS    
\ we stop here; the rest will be inaccessible junk (4 bytes).
;
 

: DrOpen  DA.prelude DiskOpen DA.epilogue ;
: DrClose DA.prelude DiskClose DA.epilogue ;
: DrCtl   DA.prelude DiskControl DA.JIODone  ; 
: DrStatus DA.prelude DiskStatus DA.JIODone ;
: DrPrime DA.prelude DiskPrime DA.JIODone ;

‘ DrOpen ‘ DrPrime ‘ DrCtl ‘ DrStatus ‘ DrClose
$6F00 0 0 0 ( flags delay mask menu )
“ .SCSIfth” ( name, MUST start with a period ) 
;DA

‘ RealInstall ;XDEF

\ ----------------------------------------------------
\ The following routines are to be added or replaced in the 
\ installer program from the previous column. Included is an
\ installer that will directly move the Forth code to disk, without
\ going through a resource, and some code to install the driver 
\ in memory for testing without writing it to the disk. The 
\ DDM and DPM definitions have been changed somewhat 
\ to accommodate the larger driver, and to have the partition start 
\ at the same place that Apple’s new SCSI driver expects it (so
\ that you can replace the Forth driver easily by a new Apple 
\ driver in case you are fed up with this hack)
\ Good luck. - JL -
\ ----------------------------------------------------

hex

: create.ddm
 ddm 200 0 fill
 4552 ddm w!
 read.cap ddm 2+ w! ( block size )
  ddm 4 + ! ( # of blocks )
 0 ddm 8 + w! ( device type )
 0 ddm A + w! ( device ID )
 10 ddm C + !  ( first data block )
 1 ddm 10 + w! ( one driver to follow )
 4 ddm 12 + ! ( driver start block )
 A ddm 16 + w! ( driver is 10 blocks long )
 1 ddm 18 + w! ( and runs on Macintosh =1 )
;
: create.dpm
 dpm 200 0 fill
 5453 dpm w!
 10 dpm 2+ ! ( starting block of partition )
 read.cap drop 10 - dpm 6 + ! ( # of blocks )
 “tfs1 dpm A + !   ( TFS1 signature )
 0 dpm E + !
;
decimal
: read.ddm
 0 read.blk 2+ w! 0 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk @ ddm 512 doscsi.r
 2drop
;
: read.dpm
 0 read.blk 2+ w! 1 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk @ dpm 512 doscsi.r
 2drop
;
: write.ddm
 0 write.blk 2+ w! 0 write.blk 4 + c!
 1 write.blk 5 + c!
 120 write.blk myDisk @ ddm 512 doscsi.w
 2drop
;
: write.dpm
 0 write.blk 2+ w! 1 write.blk 4 + c!
 1 write.blk 5 + c!
 120 write.blk myDisk @ dpm 512 doscsi.w
 2drop
;
: get.sdrv { | length -- length } 
 [‘] scsidisk dup 
 xlen dup -> length driver.block swap cmove
 length
;
: write.sdrv { length | sectors }
 0 write.blk 2+ w! 4 write.blk 4 + c!
 length 512 / 1+ dup write.blk 5 + c! -> sectors
 120 write.blk myDisk @ driver.block 
 sectors 512 * doscsi.w
 cr .” Driver written. Stat, Mess = “ . .
;

: dmp { block# | -- } ( for easy testing of SCSI disk contents )
 0 read.blk 2+ w! block# read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk @ ddm 512 doscsi.r
 2drop
 ddm 20 dump
;
  
.TRAP   _newptr,sys     $A51E
$308 CONSTANT DQHeader
6 CONSTANT QTail

VARIABLE syshp.drvr

: install.driver { | dstart dlength dbytes pointer -- }
 read.ddm 
 ddm 18 +  @ -> dstart
 ddm 22 + w@ -> dlength
 cr .” Driver starts at sector “ dstart .
 .”  and is “ dlength . .”  sectors long.”
 dlength 512 * -> dbytes
 dstart 256 /mod read.blk 2+ w! read.blk 4 + c!
 dlength read.blk 5 + c!
 120 read.blk myDisk @ driver.block dbytes doscsi.r
 cr .” Driver read; stat, mess = “ . .
 dbytes MOVE.L (A6)+,D0
      _newptr,sys ( get memory block in system heap )
      MOVE.L A0,-(A6)   -> pointer
 pointer 
 IFdriver.block pointer dbytes cmove
 pointer syshp.drvr !
      ELSE .” Not enough system heap for installation.” cr
      THEN
;
CODE call.driver
 MOVE.L D5,-(A7)
 MOVE.L (A6)+,D5
 MOVE.L (A6)+,A0
 execute
 MOVE.L (A7)+,D5
 RTS
END-CODE
 
: mount.scsi
 install.driver 
 read.dpm
 SysEvtMask @
 0 SysEvtMask !
 syshp.drvr @ dpm myDisk @ call.driver
 SysEvtMask !
;
: zero.scsi 
 DQHeader qTail + @ dQDrive + w@ ( drive # found )
 cr .” Do you want to zero the directory of drive # “ 
 dup . .”  ? “
 yesno if “ JL’s Hard Disk” call DIZero
 cr .” Result code = “ . cr 
 then
;
: mount 
 cr .” Looking for SCSI devices...”
 get.disk
 cr .” SCSI drive found at address “ myDisk @ .
 cr show.cap
 cr .” format disk? “ 
 yesno IF 
 cr .” Do you REALLY want to erase this SCSI disk? “
 yesno IF cr .” Reformatting disk... “ 
  format 
   THEN
 THEN
 modenoattn
 create.ddm create.dpm
 write.ddmwrite.dpm
 cr .” Device and partition descriptor maps written. “
 get.sdrv
 cr .” Writing driver ... “
 write.sdrv
 mount.scsi
 zero.scsi 
;
: install.mem { | dbytes pointer -- }
 get.sdrv
 [‘] scsidisk xlen dup -> dbytes
 MOVE.L (A6)+,D0
      _newptr,sys ( get memory block in system heap )
      MOVE.L A0,-(A6)   -> pointer
 pointer 
 IFdriver.block pointer dbytes cmove
 pointer syshp.drvr !
      ELSE .” Not enough system heap for installation.” cr
      THEN
;
: mount.mem
 install.mem
 read.dpm
 SysEvtMask @
 0 SysEvtMask !
 syshp.drvr @ dpm myDisk @ call.driver
 SysEvtMask !
;
 
AAPL
$97.36
Apple Inc.
+0.33
MSFT
$44.51
Microsoft Corpora
+0.11
GOOG
$587.84
Google Inc.
-5.51

MacTech Search:
Community Search:

Software Updates via MacUpdate

TinkerTool 5.3 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Audio Hijack Pro 2.11.0 - Record and enh...
Audio Hijack Pro drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio with Audio Hijack... Read more
Intermission 1.1.1 - Pause and rewind li...
Intermission allows you to pause and rewind live audio from any application on your Mac. Intermission will buffer up to 3 hours of audio, allowing users to skip through any assortment of audio... Read more
Autopano Giga 3.6 - Stitch multiple imag...
Autopano Giga allows you to stitch 2, 20, or 2,000 images. Version 3.0 integrates impressive new features that will definitely make you adopt Autopano Pro or Autopano Giga: Choose between 9... Read more
Airfoil 4.8.7 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more
Microsoft Remote Desktop 8.0.8 - Connect...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
xACT 2.30 - Audio compression toolkit. (...
xACT stands for X Aaudio Compression Toolkit, an application that encodes and decodes FLAC, SHN, Monkey’s Audio, TTA, Wavpack, and Apple Lossless files. It also can encode these formats to MP3, AAC... Read more
Firefox 31.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals... Read more
Little Snitch 3.3.3 - Alerts you to outg...
Little Snitch gives you control over your private outgoing data. Track background activityAs soon as your computer connects to the Internet, applications often have permission to send any... Read more
Thunderbird 31.0 - Email client from Moz...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more

Latest Forum Discussions

See All

New Trailer For Outcast Odyssey, A New K...
New Trailer For Outcast Odyssey, A New Kind of Card Battler Posted by Jennifer Allen on July 25th, 2014 [ permalink ] Out this Fall is a new kind of card battle game: Outcast Odyssey. | Read more »
Garfield: Survival of the Fattest Coming...
Garfield: Survival of the Fattest Coming to iOS this Fall Posted by Jennifer Allen on July 25th, 2014 [ permalink ] Who loves lasagna? Me. Also everyone’s favorite grumpy fat cat, Garfield. | Read more »
Happy Flock Review
Happy Flock Review By Andrew Fisher on July 25th, 2014 Our Rating: :: HERD IT ALL BEFOREUniversal App - Designed for iPhone and iPad Underneath the gloss of Happy Flock’s visuals is a game of very little substance. It’s cute, but... | Read more »
Square Register Updates Adds Offline Pay...
Square Register Updates Adds Offline Payments Posted by Ellis Spice on July 25th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Looking For Group – Hearthstone’s Curse...
For the first time since its release (which has thankfully been a much shorter window for iPad players than their PC counterparts), Blizzard’s wildly successful Hearthstone: Heroes of Warcraft CCG is sporting some brand new content: the single... | Read more »
Poptile Review
Poptile Review By Jennifer Allen on July 25th, 2014 Our Rating: :: SIMPLY FUNUniversal App - Designed for iPhone and iPad Simple yet a little bit glorious, Poptile is a satisfying entertaining puzzle game with oodles of the ‘one... | Read more »
Modern Combat 5: Blackout Review
Modern Combat 5: Blackout Review By Brittany Vincent on July 25th, 2014 Our Rating: :: LESS QQ, MORE PEW PEWUniversal App - Designed for iPhone and iPad The fifth entry into the blockbuster Modern Combat series is what mobile... | Read more »
Watch and Share Mobile Gameplay Videos W...
Watch and Share Mobile Gameplay Videos With Kamcord Posted by Jennifer Allen on July 25th, 2014 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
THE KING OF FIGHTERS '98 (Games)
THE KING OF FIGHTERS '98 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: Series’ masterpiece “KOF ’98” finally joins the battle on iPhone! FEATURES:■ The best game balance in the “KOF”... | Read more »
LEX Goes Free For One Day In Honor of Ne...
LEX Goes Free For One Day In Honor of New Update Posted by Jennifer Allen on July 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »

Price Scanner via MacPrices.net

iMacs on sale for $150 off MSRP, $250 off for...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
Mac minis on sale for $100 off MSRP, starting...
Best Buy has Mac minis on sale for $100 off MSRP. Choose free shipping or free instant local store pickup. Prices are for online orders only, in-store prices may vary: 2.5GHz Mac mini: $499.99 2.3GHz... Read more
Global Tablet Market Grows 11% in Q2/14 Notwi...
Worldwide tablet sales grew 11.0 percent year over year in the second quarter of 2014, with shipments reaching 49.3 million units according to preliminary data from the International Data Corporation... Read more
New iPhone 6 Models to Have Staggered Release...
Digitimes’ Cage Chao and Steve Shen report that according to unnamed sources in Apple’s upstream iPhone supply chain, the new 5.5-inch iPhone will be released several months later than the new 4.7-... Read more
New iOS App Helps People Feel Good About thei...
Mobile shoppers looking for big savings at their favorite stores can turn to the Goodshop app, a new iOS app with the latest coupons and deals at more than 5,000 online stores. In addition to being a... Read more
Save on 5th generation refurbished iPod touch...
The Apple Store has Apple Certified Refurbished 5th generation iPod touches available starting at $149. Apple’s one-year warranty is included with each model, and shipping is free. Many, but not all... Read more
What Should Apple’s Next MacBook Priority Be;...
Stabley Times’ Phil Moore says that after expanding its iMac lineup with a new low end model, Apple’s next Mac hardware decision will be how it wants to approach expanding its MacBook lineup as well... Read more
ArtRage For iPhone Painting App Free During C...
ArtRage for iPhone is currently being offered for free (regularly $1.99) during Comic-Con San Diego #SDCC, July 24-27, in celebration of the upcoming ArtRage 4.5 and other 64-bit versions of the... Read more
With The Apple/IBM Alliance, Is The iPad Now...
Almost since the iPad was rolled out in 2010, and especially after Apple made a 128 GB storage configuration available in 2012, there’s been debate over whether the iPad is a serious tool for... Read more
MacBook Airs on sale starting at $799, free s...
B&H Photo has the new 2014 MacBook Airs on sale for up to $100 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Project Manager for *Apple* Campus 2 -...
…the design and construction of one building or building components of the New Apple Campus located in Cupertino, CA. They will provide project management oversight for Read more
WW Sales Program Manager, *Apple* Online St...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.