AOH :: PRODOS.TXT

This is a compilation of a whole bunch of Prodos 8 & 16 bit technical notes..som


Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#1:    The GETLN Buffer and a ProDOS Clock Card

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note describes the effect of a clock card on the GETLN buffer.
_____________________________________________________________________________

ProDOS automatically supports a ThunderClock(TM) or compatible clock card when 
the system identifies it as being installed.  When programming under ProDOS, 
always consider the impact of a clock card on the GETLN input buffer ($200 - 
$2FF).  ProDOS can support other clocks which may also use this space.

When ProDOS calls a clock card, the card deposits an ASCII string in the GETLN 
input buffer in the form:  07,04,14,22,46,57.  This string translates as the 
following:

    07 = The month, July (01=Jan,...,12=Dec)
    04 = The day of the week, Thurs.(00=Sun,...,06=Sat)
    14 = The date (00 to 31)
    22 = The hour, 10 p.m. (00 to 23)
    46 = The minute (00 to 59)
    57 = The second (00 to 59)
    
ProDOS calls the clock card as part of many of its routines.  Anything in the 
first 17 bytes of the GETLN input buffer is subject to loss if a clock card is 
installed and is called.

In general, it has been the practice of programmers to use the GETLN input 
buffer for every conceivable purpose.  Therefore, an application should never 
store anything there.  If your application has a future need to know about the 
contents of the $200 - $2FF space, you should transfer it to some other 
location to guarantee that it will remain intact, particularly under ProDOS, 
where a clock card may regularly be overwriting the first 17 bytes.

The ProDOS 8 Technical Reference Manual contains more information on the clock 
driver, including the necessary identification bytes, how the ProDOS driver 
calls the card, and how you may replace this routine with your own.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#2:    Porting DOS 3.3 Programs to ProDOS and BASIC.SYSTEM

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note formerly described the DOSCMD vector of BASIC.SYSTEM.
_____________________________________________________________________________

This Note formerly described the DOSCMD vector of BASIC.SYSTEM, which can be 
used to let BASIC.SYSTEM interpret ASCII strings as disk commands in much the 
same way DOS 3.3 did.  The ProDOS 8 Technical Reference Manual now contains 
this information in Appendix A.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#3:    Device Search, Identification, and Driver Conventions

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note formerly described how ProDOS 8 searches for devices and 
how it deals with devices which are not Disk II drives.
_____________________________________________________________________________

This Note formerly described how ProDOS 8 searches for devices and how it 
deals with devices which are not Disk II drives; this information is now 
contained in section 6.3 of the ProDOS 8 Technical Reference Manual.

Note:    The information on slot mapping on page 113 of the manual 
and on page 2 of the former edition of this Technical Note is 
incorrect.  ProDOS itself will mirror SmartPort devices from 
slot 5 into slot 2 under certain conditions.  Devices should not 
be mirrored into slots other than slot 2.  For more information, 
see ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#4:    I/O Redirection in DOS and ProDOS

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note discusses I/O redirection differences between DOS 3.3 and 
ProDOS.
_____________________________________________________________________________

Under DOS 3.3, all that is necessary to change the I/O hooks is installing 
your I/O routine addresses in the character-out vector ($36-$37) and the key-
in vector ($38-$39) and notifying DOS (JSR $3EA) to take your addresses and 
swap in its intercept routine addresses.

Under ProDOS, there is no instruction installed at $3EA, so what do you do?

You simply leave the ProDOS BASIC command interpreter's intercept addresses 
installed at $36-$39 and install your I/O addresses in the global page at 
$BE30-$BE33.  The locations $BE30-$BE31 should contain the output address 
(normally $FDF0, the Monitor COUT1 routine), while $BE32-$BE33 should contain 
the input address (normally $FD1B, the Monitor KEYIN routine).

By keeping these vectors in a global page, a special routine for  moving the 
vectors is no longer needed, thus, no $3EA instruction.  You install the 
addresses at their destination yourself.

If you intend to switch between devices (i.e., the screen and the printer), 
you should save the hooks you find in $BE30-$BE33 and restore them when you 
are done.  Blindly replacing the values in the global page could easily leave 
you no way to restore input or output to the previous device when you are 
done.


Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#5:    ProDOS Block Device Formatting

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                     October 1985

This Technical Note formerly described the ProDOS FORMATTER routine.
_____________________________________________________________________________

The ProDOS 8 Update Manual now contains the information about the ProDOS 
FORMATTER routine which this Note formerly described.  This routine is 
available from Apple Software Licensing at Apple Computer, Inc., 20525 Mariani 
Avenue, M/S 38-I, Cupertino, CA, 95014 or (408) 974-4667.

Note:    This routine does not work properly with network volumes on 
either entry point.  You cannot format a network volume with 
ProDOS 8, nor can you make low-level device calls to it (as 
FORMATTER does in ENTRY2 to determine the characteristics of a 
volume).  As a general rule, it is better to use GET_FILE_INFO to 
determine the size of the volume since ProDOS MLI calls work with 
network volumes.


Further Reference
o    ProDOS 8 Update Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#6:    Attaching External Commands to BASIC.SYSTEM

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    December 1985

This Technical Note formerly described how to attach an external command to 
BASIC.SYSTEM.
_____________________________________________________________________________

The ProDOS 8 Technical Reference Manual, Appendix A now documents the 
information which this Note formerly covered about installing an external 
command into BASIC.SYSTEM to be treated as a normal BASIC.SYSTEM command.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#7:    Starting and Quitting Interpreter Conventions

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    December 1985

This Technical Note formerly described conventions for a ProDOS application to 
start and quit.
_____________________________________________________________________________

Section 5.1.5 of the ProDOS 8 Technical Reference Manual now documents the 
conventions a ProDOS application should follow when starting and quitting, 
which were formerly covered in this Note as well as ProDOS 8 Technical Note 
#14, Selector and Dispatcher Conventions.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#8:    Dealing with /RAM

Revised by:    Matt Deatherage                                  November 1988
Written by:    Kerry Laidlaw                                     October 1984

This Technical Note formerly described conventions for dealing with the built-
in ProDOS 8 RAM disk, /RAM.
_____________________________________________________________________________

Section 5.2.2 of the ProDOS 8 Technical Reference Manual now documents the 
conventions on how to handle /RAM, including how to disconnect it, how to 
reconnect it, and precautions you should follow if doing either, which were 
covered in this Note.  The manual also includes sample source code.

Executing the sample code which comes with the manual to disconnect /RAM has 
the undesired effect of decreasing the maximum number of volumes on-line when 
used with versions of ProDOS 8 prior to 1.2.  This side effect is because 
earlier versions of ProDOS 8 do not have the capability to remove the volume 
control block (VCB) entry which is allocated for /RAM when it is installed.

In later versions of ProDOS 8 (1.2 and later), this problem no longer exists, 
and you should issue an ON_LINE call to a device after disconnecting it.  This 
call returns error $28 (no device connected), but it also erases the VCB entry 
for the disconnected device.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Update Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#9:    Buffer Management Using BASIC.SYSTEM

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                     October 1985

This Technical Note discusses methods for allocating buffers which will not be 
arbitrarily deallocated in BASIC.SYSTEM.
_____________________________________________________________________________

Section A.2.1 of the ProDOS 8 Technical Reference Manual describes in detail 
how an application may obtain a buffer from BASIC.SYSTEM for its own use.  The 
buffer will be respected by BASIC.SYSTEM, so if you choose to put a program or 
other executable code in there, it will be safe.

However, BASIC.SYSTEM does not provide a way to selectively deallocate the 
buffers it has allocated.  Although it is quite easy to allocate space by 
calling GETBUFR ($BEF5) and also quite easy to deallocate by calling FREEBUFR 
($BEF8), it is not so easy to use FREEBUFR to deallocate a particular buffer.

In fact, FREEBUFR always deallocates all buffers allocated by GETBUFR.  This 
is fine for transient applications, but a method is needed to protect a static 
code buffer from being deallocated by FREEBUFR for a static application.

Location RSHIMEM ($BEFB) contains the high byte of the highest available 
memory location for buffers, normally $96.  FREEBUFR uses it to determine the 
beginning page of the highest (or first) buffer.  By lowering the value of 
RSHIMEM immediately after the first call to GETBUFR, and before any call to 
FREEBUFR, we can fool FREEBUFR into not reclaiming all the space.  So although 
it is not possible to selectively deallocate buffers, it is still possible to 
reserve space that FREEBUFR will not reclaim.

Physically, we place the code buffer between BASIC.SYSTEM and its buffers, in 
the space from $99FF down.

After creating the protected static code buffer, we can call GETBUFR and 
FREEBUFR to maintain temporary buffers as needed by our protected module.  
FREEBUFR will not reclaim the protected buffer until after RSHIMEM is restored 
to its original value.

The following is a skeleton example which allocates a two-page buffer for a 
static code module, protects it from FREEBUFR, then deprotects it and restores 
it to its original state.

START    LDA #$02            ;get 2 pages
         JSR GETBUFR 
         LDA RSHIMEM         ;get current RSHIMEM
         SEC                 ;ready for sub
         SBC #$02            ;minus 2 pages
         STA RSHIMEM         ;save new val to fool FREEBUFR
         JSR FREEBUFR        ;CALL FREEBUFR to deallocate.

At this point, the value of RSHIMEM is the page number of the beginning of our 
protected buffer.  The static code may now use GETBUFR and FREEBUFR for 
transient file buffers without fear of freeing its own space from RSHIMEM to 
$99FF.

To release the protected space, simply restore RSHIMEM to its original value 
and perform a JSR FREEBUFR.

END      LDA RSHIMEM         ;get current val
         CLC                 ;ready for ADD
         ADC #2              ;give back 2 pages
         STA RSHIMEM         ;tell FREEBUFR about it
         JSR FREEBUFR        ;DO FREEBUFR
         RTS 

You can reserve any number of pages using this method, as long as the amount 
you reserve is within available memory limits. 


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#10:    Installing Clock Driver Routines

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note formerly described how to install a clock driver routine 
other than the default.
_____________________________________________________________________________

Section 6.1.1 of the ProDOS 8 Technical Reference Manual documents how to 
install a clock driver other than the default ThunderClock(TM) driver or the 
Apple IIGS clock driver into ProDOS 8, which this Note formerly covered.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Technical Note #1, The GETLN Buffer and a ProDOS Clock Card
Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#11:    The ProDOS 8 MACHID Byte

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note describes the machine ID byte (MACHID) which ProDOS 
maintains to help identify different machine types.
_____________________________________________________________________________

ProDOS 8 maintains a machine ID byte, MACHID, at location $BF98 in the ProDOS 
8 global page.  Section 5.2.4 of the ProDOS 8 Technical Reference Manual 
correctly documents the definition of this byte.

MACHID has become less robust through the years.  Although it can tell you if 
you are running on an Apple ][, ][+, IIe, IIc, or Apple /// in emulation mode, 
it cannot tell you which version of an Apple IIe or IIc you are using, nor can 
it identify an Apple IIGS (it thinks a IIGS is an Apple IIe).  However, the 
byte still provides a quick test for two components of the system which you 
might wish to identify:  an 80-column card and a clock card.

Bit 1 of MACHID identifies an 80-column card.  ProDOS 8 Technical Note #15, 
How ProDOS 8 Treats Slot 3 explains how this identification is determined.  
Note that on an Apple IIGS, this bit is always set, even if the user selects 
Your Card in the Control Panel for slot 3.  The bit is set since ProDOS 8 
versions 1.7 and later switch out a card in slot 3 in favor of the built-in 
80-column firmware, unless the card in slot 3 is an 80-column card.  ProDOS 8 
behaves in the same manner on an Apple IIe as well.

Bit 0 of MACHID identifies a clock card.  Note that on an Apple IIGS, this bit 
is always set since the IIGS clock cannot be switched out of the system.  Due 
to these unchangeable settings, the value of MACHID on the Apple IIGS is 
always $B3, as it is on any Apple IIe with an 80-column card and a clock card.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    Apple IIGS Hardware Reference Manual
o    ProDOS 8 Technical Note #15, How ProDOS 8 Treats Slot 3
o    Miscellaneous Technical Note #7, Apple II Family Identification

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#12:    Interrupt Handling

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note clarifies some aspects of ProDOS 8 interrupt handlers.
_____________________________________________________________________________

Although the ProDOS 8 Technical Reference Manual (section 6.2) documents 
interrupt handlers and includes a code example, there still remain a few 
unclear areas on this subject matter; this Note clarifies these areas.

All interrupt routines must begin with a CLD instruction.  Although not 
checked in initial releases of ProDOS 8, this first byte will be checked in 
future revisions to verify the validity of the interrupt handler.

Although your interrupt handler does not have to disable interrupts (ProDOS 8 
does that for you), it must never re-enable interrupts with a 6502 CLI 
instruction.  Another interrupt coming through during a non-reentrant 
interrupt handler can bring the system down.

If your application includes an interrupt handler, you should do the following 
before exiting:

1.    Turn off the interrupt source.  Remember, 255 unclaimed interrupts 
      will cause system death.
2.    Make a DEALLOC_INTERRUPT call before exiting from your 
      application.  Do not leave a vector installed that points to a 
      routine that is no longer there.

Within your interrupt handler routines, you must leave all memory banks in the 
same configuration you found them.  Do not forget anything:  main language 
card, main alternate $D000 space, main motherboard ROM, and, on an Apple IIe, 
IIc, or IIGS, auxiliary language card, auxiliary alternate $D000 space, 
alternate zero page and stack, etc.  This is very important since the ProDOS 
interrupt receiver assumes that the environment is absolutely unaltered when 
your handler relinquishes control.  In addition, be sure to leave the language 
card write-enabled.

If your handler recognizes an interrupt and services it, you should clear the 
carry flag (CLC) immediately before returning (RTS).  If it was not your 
interrupt, you set set the carry (SEC) immediately before returning (RTS).  Do 
not use a return from interrupt (RTI) to exit; the ProDOS interrupt receiver 
still has some housekeeping to perform before it issues the RTI instruction.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#13:    Double High-Resolution Graphics Files

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note formerly described a proposed file format for Apple II 
double high-resolution graphics images.
_____________________________________________________________________________

The information formerly in this Note, the proposed file format for Apple II 
double high-resolution graphics images, is now covered in the Apple II File 
Type Notes, File Type $08.


Further Reference
o    Apple II File Type Notes, File Type $08

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#14:    Selector and Dispatcher Conventions

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    December 1985

This Technical Note formerly described conventions for a ProDOS application to 
start and quit.
_____________________________________________________________________________

Section 5.1.5 of the ProDOS 8 Technical Reference Manual now documents the 
conventions a ProDOS application should follow when starting and quitting, 
which were formerly covered in this Note as well as ProDOS 8 Technical Note 
#7, Starting and Quitting Interpreter Conventions.


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#15:    How ProDOS 8 Treats Slot 3

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note describes how ProDOS 8 reacts to non-Apple 80-column cards 
in slot 3 and how it identifies them.
_____________________________________________________________________________

The ProDOS 8 Update Manual now documents much of the information which was 
originally covered in this Note about how ProDOS 8 reacts to non-Apple 80-
column cards in slot 3.  However, since there is still some confusion on the 
issue, we summarize it again in this Note.

On an Apple ][+, ProDOS 8 considers the following four Pascal 1.1 protocol ID 
bytes sufficient to identify a card in slot 3 as an 80-column card and mark 
the corresponding bit in the MACHID byte:  $C305 = $38, $C307 = $18, $C30B = 
$01, $C30C = $8x, where x represents the card's own ID value and is not 
checked.  On any other Apple II, the following fifth ID byte must also match:  
$C3FA = $2C.  This fifth ID byte assures ProDOS 8 that the card supports 
interrupts on an Apple IIe.  Unless ProDOS 8 finds all five ID bytes in an 
Apple IIe or later, it will not identify the card as an 80-column card and 
will enable the built-in 80-column firmware instead.  In an Apple IIc or IIGS, 
the internal firmware always matches these five bytes (see below).

If you are designing an 80-column card and wish to meet these requirements, 
you must follow certain other considerations as well as matching the five 
identification bytes; the ProDOS 8 Update Manual enumerates these other 
considerations.

The ProDOS 8 Update Manual notes that an Apple IIGS does not switch in the 80-
column firmware if it is not selected in the Control Panel.  However, due to a 
bug in ProDOS 8 versions 1.6 and earlier, it switches in the 80-column 
firmware unconditionally.  ProDOS 8 cannot respect the Control Panel setting 
for 80-column firmware in certain situations; it cannot operate in a 128K 
machine in a 128K configuration (including /RAM) without the presence of the 
80-column firmware, since it must utilize the extra 64K.  This is just one of 
the reasons ProDOS 8 does not recognize a card in slot 3 if it is not an 80-
column card, as outlined above.

With ProDOS 8 version 1.7 and later, an Apple IIGS behaves exactly like an 
Apple IIe with respect to slot 3.  If a card is slot 3 is selected in the 
Control Panel, ProDOS 8 ignores it in favor of the built-in 80-column 
firmware--unless the card matches the five identification bytes listed above.  
This works the same on a Apple IIe.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Update Manual
o    ProDOS 8 Technical Note #11, The ProDOS 8 MACHID Byte

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#16:    How to Format a ProDOS Disk Device

Revised by:    Matt Deatherage                                  November 1988
Revised by:    Pete McDonald                                    November 1985

This Technical Note supplements the ProDOS 8 Technical Reference Manual in its 
description of the low-level driver call that formats the media in a ProDOS 
device.
_____________________________________________________________________________

The ProDOS 8 Technical Reference Manual describes the low-level driver call 
that formats the media in a ProDOS device, but it neglects to mention the 
following:

1.    It does not work for Disk II drives or /RAM, both of which ProDOS 
      treats specially with built-in driver code.
2.    ProDOS has no easy way to tell you whether a device is a Disk II 
      drive or /RAM.

Once ProDOS finishes building its device table, which it does when it boots, 
it no longer cares about what kind of devices exist, so it does not keep any 
information about the different types of devices available.  ProDOS identifies 
Disk II devices and installs a built-in driver for them.  When it has 
installed all devices which are physically present, ProDOS then installs /RAM, 
in a manner similar to Disk II drives, by pointing to the driver code which is 
within ProDOS itself.  This method presents a problem for the developer who 
wishes to format ProDOS disks since the Disk II driver and the /RAM driver 
respond to the FORMAT request in non-standard ways, yet there is no 
identification in the global page that tells you which devices are Disk II 
drives or /RAM.

The Disk II driver does not support the FORMAT request, and the /RAM driver 
responds by "formatting" the RAM disk and also writing to it a virgin 
directory and bitmap; neither of these two cases is documented in the ProDOS 8 
Technical Reference Manual.  To write special-case code for these two device 
types, you must be able to identify them, and the method for identification is 
available in ProDOS 8 Technical Note #21:  Identifying ProDOS Devices.

You should note, however, that AppleTalk network volumes cannot be formatted; 
they return a DEVICE NOT CONNECTED error for the FORMAT and any low-level 
device call.  You may access AppleTalk network volumes through ProDOS MLI 
calls only.

Also note that Apple licences a ProDOS 8 Formatter routine, which correctly 
identifies and handles Disk II drives and /RAM.  You should contact Apple 
Software Licensing at Apple Computer, Inc., 20525 Mariani Avenue, M/S 38-I, 
Cupertino, CA, 95014 or (408) 974-4667 if you wish to license this routine.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Update Manual
o    ProDOS 8 Technical Note #21, Identifying ProDOS Devices
Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#17:    Recursive ProDOS Catalog Routine

Revised by:    Keith Rollin & Matt Deatherage                   November 1988
Written by:    Greg Seitz                                       December 1983

This Technical Note presents an assembly language example of a recursive 
directory reading routine which is AppleShare compatible.
_____________________________________________________________________________

This Note presents a routine in assembly language for recursively cataloging a 
ProDOS disk, and if you apply this technique to the volume directory of a 
disk, it will display the name of every file stored on the disk.  The routine 
displays the contents of a given directory, the volume directory in this case, 
then displays the contents of every directory contained within the initial 
directory.

Previous versions of the Note recommended reading the directory with 
READ_BLOCK ProDOS calls.  This method will still work in most cases, but Apple 
Computer no longer endorses it since block-level access is not allowed to 
AppleShare file servers under ProDOS.  (A file server cannot handle one 
machine connected to it changing files and directories on a block level while 
it is trying to arbitrate usage between other machines at the file level.  A 
block-level change behind the server's back could easily mess things up 
catastrophically.)

If you are willing to use a different approach, however, you can read the 
directory just as easily using READ calls.  Instead of using directory 
pointers to decide which block to read next, we simply read the directory and 
display filenames as we go, until we reach a subdirectory file.  When we reach 
a subdirectory, the routine saves the necessary variables, plunges down one 
level of the tree structure, and catalogs the subdirectory.  You repeat the 
process if you find a subdirectory at the current level.  When you reach the 
EOF of any directory, the routine closes the current directory and pops back 
up one level, and when it reaches the EOF of the initial directory, the 
routine is finished.

The code example on the following pages includes a simple test of the ReadDir 
routine, which is the actual recursive catalog routine.  Note that the simple 
test relies upon the GETBUFR routine in BASIC.SYSTEM to allocate a buffer; 
therefore, as presented, the routine requires the presence of BASIC.SYSTEM.  
The actual ReadDir routine requires nothing outside of the ProDOS 8 MLI.



01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 2
 
----- NEXT OBJECT FILE NAME IS CATALOG.OBJ                   
0800:        0800    2           org   $800
0800:                3 *******************************************************
0800:                4 *
0800:                5 * Recursive ProDOS Catalog Routine
0800:                6 *
0800:                7 * by: Greg Seitz 12/83
0800:                8 *     Pete McDonald 1/86
0800:                9 *     Keith Rollin 7/88
0800:               10 *
0800:               11 * This program shows the latest "Apple Approved"
0800:               12 * method for reading a ProDOS directory. With
0800:               13 * the advent of AppleTalk for the Apple II, using
0800:               14 * _READBLOCK to read the directory will no longer
0800:               15 * work. This routine has been re-written to read
0800:               16 * directories by opening them as files, and
0800:               17 * performing simple _READ commands.
0800:               18 *
0800:               19 *******************************************************
0800:               20 *
0800:               21 * Equates
0800:               22 *
0800:               23 * Zero page locations
0800:               24 *
0800:        0080   25 dirName   equ   $80           ; pointer to directory name
0800:        0082   26 entPtr    equ   $82           ; ptr to current entry
0800:               27 *
0800:               28 *
0800:               29 * ProDOS command numbers
0800:               30 *
0800:        BF00   31 MLI       equ   $BF00         ; MLI entry point
0800:        BEF5   32 GetBufr   equ   $BEF5         ; BASIC.SYSTEM get buffer routine
0800:               33 *
0800:        00C7   34 GetPCmd   equ   $C7           ; Get Prefix
0800:        00C8   35 OpenCmd   equ   $C8           ; Open a file command
0800:        00CA   36 ReadCmd   equ   $CA           ; Read a file command
0800:        00CC   37 CloseCmd  equ   $CC           ; Close a file command
0800:        00CE   38 SetMCmd   equ   $CE           ; Set File Position command
0800:               39 *
0800:               40 *
0800:               41 * Offsets into the directory
0800:               42 *
0800:        0000   43 oType     equ   $0            ; offset to file type byte
0800:        0023   44 oEntLen   equ   $23           ; length of each dir. entry
0800:        0024   45 oEntBlk   equ   $24           ; entries in each block
0800:        0025   46 oEntDir   equ   $25           ; entries in entire directory
0800:               47 *
0800:               48 *
0800:               49 * Monitor routines
0800:               50 *
0800:        FDED   51 cout      equ   $FDED         ; output a character
0800:        FD8E   52 crout     equ   $FD8E         ; output a RETURN
0800:               53 *
0800:               54 *******************************************************
0800:               55 *
0800:        0800   56 Start     equ   *
0800:               57 *
0800:               58 * Simple routine to test the recursive ReadDir

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 3
 
0800:               59 * routine. It gets an I/O buffer for ReadDir, gets
0800:               60 * the current prefix, sets the depth of recursion
0800:               61 * to zero, and calls ReadDir to process all of the
0800:               62 * entries in the directory.
0800:               63 *
0800:A9 04          64           lda   #4            ; get an I/O buffer
0802:20 F5 BE       65           jsr   GetBufr
0805:B0 17   081E   66           bcs   exit          ; didn't get it
0807:8D DD 09       67           sta   ioBuf+1
080A:               68 *
080A:20 00 BF       69           jsr   MLI
080D:C7             70           db    GetPCmd
080E:EE 09          71           dw    GetPParms
0810:B0 0C   081E   72           bcs   exit
0812:               73 *
0812:A9 00          74           lda   #0
0814:8D D2 09       75           sta   Depth
0817:               76 *
0817:A9 F1          77           lda   #nameBuffer
0819:A2 0B          78           ldx   #<nameBuffer
081B:20 1F 08       79           jsr   ReadDir
081E:               80 *
081E:        081E   81 exit      equ   *
081E:60             82           rts
081F:               83 *
081F:               84 *******************************************************
081F:               85 *
081F:        081F   86 ReadDir   equ   *
081F:               87 *
081F:               88 *  This is the actual recursive routine. It takes as
081F:               89 *  input a pointer to the directory name to read in
081F:               90 *  A,X (lo,hi), opens it, and starts to read the
081F:               91 *  entries. When it encounters a filename, it calls
081F:               92 *  the routine "VisitFile". When it encounters a
081F:               93 *  directory name, it calls "VisitDir".
081F:               94 *
081F:               95 *******************************************************
081F:               96 *
081F:85 80          97           sta   dirName       ; save a pointer to name
0821:86 81          98           stx   dirName+1
0823:               99 *
0823:8D DA 09      100           sta   openName      ; set up OpenFile params
0826:8E DB 09      101           stx   openName+1
0829:              102 *
0829:        0829  103 ReadDir1  equ   *             ; recursive entry point
0829:20 54 08      104           jsr   OpenDir       ; open the directory as a file
082C:B0 1F   084D  105           bcs   done
082E:              106 *
082E:4C 48 08      107           jmp   nextEntry     ; jump to the end of the loop
0831:              108 *
0831:        0831  109 loop      equ   *
0831:A0 00         110           ldy   #oType        ; get type of current entry
0833:B1 82         111           lda   (entPtr),y
0835:C9 00         112           cmp   #0            ; inactive entry?
0837:F0 0F   0848  113           beq   nextEntry     ; yes - bump to next one
0839:29 F0         114           and   #$F0          ; look at 4 high bits
083B:C9 D0         115           cmp   #$D0          ; is it a directory?
083D:F0 06   0845  116           beq   ItsADir       ; yes, so call VisitDir

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 4
 
083F:20 9A 08      117           jsr   VisitFile     ; no, it's a file
0842:4C 48 08      118           jmp   nextEntry
0845:        0845  119 ItsADir   equ   *
0845:20 A1 08      120           jsr   VisitDir
0848:        0848  121 nextEntry equ   *
0848:20 68 09      122           jsr   GetNext       ; get pointer to next entry
084B:90 E4   0831  123           bcc   loop          ; Carry set means we're done
084D:        084D  124 done      equ   *
084D:              125 *
084D:20 00 BF      126           jsr   MLI           ; close the directory
0850:CC            127           db    CloseCmd
0851:E7 09         128           dw    CloseParms
0853:              129 *
0853:60            130           rts
0854:              131 *
0854:              132 *******************************************************
0854:              133 *
0854:        0854  134 OpenDir   equ   *
0854:              135 *
0854:              136 *  Opens the directory pointed to by OpenParms
0854:              137 *  parameter block. This pointer should be init-
0854:              138 *  ialized BEFORE this routine is called. If the
0854:              139 *  file is successfully opened, the following
0854:              140 *  variables are set:
0854:              141 *
0854:              142 *     xRefNum     ; all the refnums
0854:              143 *     entryLen    ; size of directory entries
0854:              144 *     entPtr      ; pointer to current entry
0854:              145 *     ThisBEntry  ; entry number within this block
0854:              146 *     ThisEntry   ; entry number within this dir.
0854:              147 *     ThisBlock   ; offset (in blocks) into dir.
0854:              148 *
0854:20 00 BF      149           jsr   MLI           ; open dir as a file
0857:C8            150           db    OpenCmd
0858:D9 09         151           dw    OpenParms
085A:B0 3D   0899  152           bcs   OpenDone
085C:              153 *
085C:AD DE 09      154           lda   oRefNum       ; copy the refnum return-
085F:8D E0 09      155           sta   rRefNum       ; ed by Open into the
0862:8D E8 09      156           sta   cRefNum       ; other param blocks.
0865:8D EA 09      157           sta   sRefNum
0868:              158 *
0868:20 00 BF      159           jsr   MLI           ; read the first block
086B:CA            160           db    ReadCmd
086C:DF 09         161           dw    ReadParms
086E:B0 29   0899  162           bcs   OpenDone
0870:              163 *
0870:AD 14 0A      164           lda   buffer+oEntLen ; init 'entryLen'
0873:8D D7 09      165           sta   entryLen
0876:              166 *
0876:A9 F5         167           lda   #buffer+4     ; init ptr to first entry
0878:85 82         168           sta   entPtr
087A:A9 09         169           lda   #<buffer+4
087C:85 83         170           sta   entPtr+1
087E:              171 *
087E:AD 15 0A      172           lda   buffer+oEntblk ; init these values based on
0881:8D D5 09      173           sta   ThisBEntry    ; values in the dir header
0884:8D D8 09      174           sta   entPerBlk

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 5
 
0887:AD 16 0A      175           lda   buffer+oEntDir
088A:8D D3 09      176           sta   ThisEntry
088D:AD 17 0A      177           lda   buffer+oEntDir+1
0890:8D D4 09      178           sta   ThisEntry+1
0893:              179 *
0893:A9 00         180           lda   #0            ; init block offset into dir.
0895:8D D6 09      181           sta   ThisBlock
0898:              182 *
0898:18            183           clc                 ; say that open was OK
0899:              184 *
0899:        0899  185 OpenDone  equ   *
0899:60            186           rts
089A:              187 *
089A:              188 *******************************************************
089A:              189 *
089A:        089A  190 VisitFile equ   *
089A:              191 *
089A:              192 * Do whatever is necessary when we encounter a
089A:              193 * file entry in the directory. In this case, we
089A:              194 * print the name of the file.
089A:              195 *
089A:20 A7 09      196           jsr   PrintEntry
089D:20 8E FD      197           jsr   crout
08A0:60            198           rts
08A1:              199 *
08A1:              200 *******************************************************
08A1:              201 *
08A1:        08A1  202 VisitDir  equ   *
08A1:              203 *
08A1:              204 * Print the name of the subdirectory we are looking
08A1:              205 * at, appending a "/" to it (to indicate that it's
08A1:              206 * a directory), and then calling RecursDir to list
08A1:              207 * everything in that directory.
08A1:              208 *
08A1:20 A7 09      209           jsr   PrintEntry    ; print dir's name
08A4:A9 AF         210           lda   #'/'|$80      ; tack on / at end
08A6:20 ED FD      211           jsr   cout
08A9:20 8E FD      212           jsr   crout
08AC:              213 *
08AC:20 B0 08      214           jsr   RecursDir     ; enumerate all entries in sub-dir.
08AF:              215 *
08AF:60            216           rts
08B0:              217 *
08B0:              218 *******************************************************
08B0:              219 *
08B0:        08B0  220 RecursDir equ   *
08B0:              221 *
08B0:              222 * This routine calls ReadDir recursively. It
08B0:              223 *
08B0:              224 * - increments the recursion depth counter,
08B0:              225 * - saves certain variables onto the stack
08B0:              226 * - closes the current directory
08B0:              227 * - creates the name of the new directory
08B0:              228 * - calls ReadDir (recursively)
08B0:              229 * - restores the variables from the stack
08B0:              230 * - restores directory name to original value
08B0:              231 * - re-opens the old directory
08B0:              232 * - moves to our last position within it

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 6
 
08B0:              233 * - decrements the recursion depth counter
08B0:              234 *
08B0:EE D2 09      235           inc   Depth         ; bump this for recursive call
08B3:              236 *
08B3:              237 * Save everything we can think of (the women,
08B3:              238 * the children, the beer, etc.).
08B3:              239 *
08B3:A5 82         240           lda   entPtr
08B5:48            241           pha
08B6:A5 83         242           lda   entPtr+1
08B8:48            243           pha
08B9:AD D3 09      244           lda   ThisEntry
08BC:48            245           pha
08BD:AD D4 09      246           lda   ThisEntry+1
08C0:48            247           pha
08C1:AD D5 09      248           lda   ThisBEntry
08C4:48            249           pha
08C5:AD D6 09      250           lda   ThisBlock
08C8:48            251           pha
08C9:AD D7 09      252           lda   entryLen
08CC:48            253           pha
08CD:AD D8 09      254           lda   entPerblk
08D0:48            255           pha
08D1:              256 *
08D1:              257 * Close the current directory, as ReadDir will
08D1:              258 * open files of its own, and we don't want to 
08D1:              259 * have a bunch of open files lying around.
08D1:              260 *
08D1:20 00 BF      261           jsr   MLI
08D4:CC            262           db    CloseCmd
08D5:E7 09         263           dw    CloseParms
08D7:              264 *
08D7:20 20 09      265           jsr   ExtendName    ; make new dir name
08DA:              266 *
08DA:20 29 08      267           jsr   ReadDir1      ; enumerate the subdirectory
08DD:              268 *
08DD:20 56 09      269           jsr   ChopName      ; restore old directory name
08E0:              270 *
08E0:20 54 08      271           jsr   OpenDir       ; re-open it back up
08E3:              272 *
08E3:              273 * Restore everything that we saved before
08E3:              274 *
08E3:68            275           pla
08E4:8D D8 09      276           sta   entPerBlk
08E7:68            277           pla
08E8:8D D7 09      278           sta   entryLen
08EB:68            279           pla
08EC:8D D6 09      280           sta   Thisblock
08EF:68            281           pla
08F0:8D D5 09      282           sta   ThisBEntry
08F3:68            283           pla
08F4:8D D4 09      284           sta   ThisEntry+1
08F7:68            285           pla
08F8:8D D3 09      286           sta   ThisEntry
08FB:68            287           pla
08FC:85 83         288           sta   entPtr+1
08FE:68            289           pla
08FF:85 82         290           sta   entPtr

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 7
 
0901:              291 *
0901:AD D6 09      292           lda   ThisBlock     ; reset last position in dir
0904:0A            293           asl   a             ; = to block # times 512
0905:8D EC 09      294           sta   Mark+1
0908:A9 00         295           lda   #0
090A:8D EB 09      296           sta   Mark
090D:8D ED 09      297           sta   Mark+2
0910:              298 *
0910:20 00 BF      299           jsr   MLI           ; reset the file marker
0913:CE            300           db    SetMCmd
0914:E9 09         301           dw    SetMParms
0916:              302 *
0916:20 00 BF      303           jsr   MLI           ; now read in the block we
0919:CA            304           db    ReadCmd       ; were on last.
091A:DF 09         305           dw    ReadParms
091C:              306 *
091C:CE D2 09      307           dec   Depth
091F:60            308           rts
0920:              309 *
0920:              310 *******************************************************
0920:              311 *
0920:        0920  312 ExtendName equ  *
0920:              313 *
0920:              314 * Append the name in the current directory entry
0920:              315 * to the name in the directory name buffer. This
0920:              316 * will allow us to descend another level into the
0920:              317 * disk hierarchy when we call ReadDir.
0920:              318 *
0920:A0 00         319           ldy   #0            ; get length of string to copy
0922:B1 82         320           lda   (entPtr),y    
0924:29 0F         321           and   #$0F
0926:8D 53 09      322           sta   extCnt        ; save the length here
0929:8C 54 09      323           sty   srcPtr        ; init src ptr to zero
092C:              324 *
092C:A0 00         325           ldy   #0            ; init dest ptr to end of
092E:B1 80         326           lda   (dirName),y   ; the current directory name
0930:8D 55 09      327           sta   destPtr
0933:              328 *
0933:        0933  329 extloop   equ   *
0933:EE 54 09      330           inc   srcPtr        ; bump to next char to read
0936:EE 55 09      331           inc   destPtr       ; bump to next empty location
0939:AC 54 09      332           ldy   srcPtr        ; get char of sub-dir name
093C:B1 82         333           lda   (entPtr),y
093E:AC 55 09      334           ldy   destPtr       ; tack on to end of cur. dir.
0941:91 80         335           sta   (dirName),y
0943:CE 53 09      336           dec   extCnt        ; done all chars?
0946:D0 EB   0933  337           bne   extloop       ; no - so do more
0948:              338 *
0948:C8            339           iny
0949:A9 2F         340           lda   #'/'          ; tack "/" on to the end
094B:91 80         341           sta   (dirName),y
094D:              342 *
094D:98            343           tya                 ; fix length of filename to open
094E:A0 00         344           ldy   #0
0950:91 80         345           sta   (dirName),y
0952:              346 *
0952:60            347           rts
0953:              348 *

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 8
 
0953:        0001  349 extCnt    ds    1
0954:        0001  350 srcPtr    ds    1
0955:        0001  351 destPtr   ds    1
0956:              352 *
0956:              353 *
0956:              354 *******************************************************
0956:              355 *
0956:        0956  356 ChopName  equ   *
0956:              357 *
0956:              358 * Scans the current directory name, and chops
0956:              359 * off characters until it gets to a /.
0956:              360 *
0956:A0 00         361           ldy   #0            ; get len of current dir.
0958:B1 80         362           lda   (dirName),y
095A:A8            363           tay
095B:        095B  364 ChopLoop  equ   *
095B:88            365           dey                 ; bump to previous char
095C:B1 80         366           lda   (dirName),y
095E:C9 2F         367           cmp   #'/'
0960:D0 F9   095B  368           bne   ChopLoop
0962:98            369           tya
0963:A0 00         370           ldy   #0
0965:91 80         371           sta   (dirName),y
0967:60            372           rts
0968:              373 *
0968:              374 *******************************************************
0968:              375 *
0968:        0968  376 GetNext   equ   *
0968:              377 *
0968:              378 * This routine is responsible for making a pointer
0968:              379 * to the next entry in the directory. If there are
0968:              380 * still entries to be processed in this block, then
0968:              381 * we simply bump the pointer by the size of the
0968:              382 * directory entry. If we have finished with this
0968:              383 * block, then we read in the next block, point to
0968:              384 * the first entry, and increment our block counter.
0968:              385 *
0968:AD D3 09      386           lda   ThisEntry     ; dec total entries
096B:D0 05   0972  387           bne   skip1
096D:CE D4 09      388           dec   ThisEntry+1
0970:30 33   09A5  389           bmi   DirDone       ; done with this directory
0972:CE D3 09      390 skip1     dec   ThisEntry
0975:              391 *
0975:CE D5 09      392           dec   ThisBEntry    ; dec count for this block
0978:F0 10   098A  393           beq   ReadNext      ; done w/this block, get next one
097A:              394 *
097A:18            395           clc                 ; else bump up index
097B:A5 82         396           lda   entPtr
097D:6D D7 09      397           adc   entryLen
0980:85 82         398           sta   entPtr
0982:A5 83         399           lda   entPtr+1
0984:69 00         400           adc   #0
0986:85 83         401           sta   entPtr+1
0988:18            402           clc                 ; say that the buffer's good
0989:60            403           rts
098A:              404 *
098A:        098A  405 ReadNext  equ   *
098A:20 00 BF      406           jsr   MLI           ; get the next block

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 9
 
098D:CA            407           db    ReadCmd
098E:DF 09         408           dw    ReadParms
0990:B0 13   09A5  409           bcs   DirDone
0992:              410 *
0992:A9 F5         411           lda   #buffer+4     ; set entry pointer to beginning
0994:85 82         412           sta   entPtr
0996:A9 09         413           lda   #<buffer+4
0998:85 83         414           sta   entPtr+1
099A:              415 *
099A:AD D8 09      416           lda   entPerBlk     ; re-init 'entries in this block'
099D:8D D5 09      417           sta   ThisBEntry
09A0:CE D5 09      418           dec   ThisBEntry
09A3:18            419           clc                 ; return 'No error'
09A4:60            420           rts
09A5:              421 *
09A5:        09A5  422 DirDone   equ   *             ; return 'All Done!'
09A5:38            423           sec                 ; return 'an error occurred'
09A6:60            424           rts
09A7:              425 *
09A7:              426 *******************************************************
09A7:              427 *
09A7:        09A7  428 PrintEntry equ  *
09A7:              429 *
09A7:              430 * Using the pointer to the current entry, this 
09A7:              431 * routine prints the entry name. It also pays
09A7:              432 * attention to the recursion depth, and indents
09A7:              433 * by 1 space for every level.
09A7:              434 *
09A7:AD D2 09      435           lda   Depth         ; init counter for indenting
09AA:8D D1 09      436           sta   PrntCnt
09AD:4C B5 09      437           jmp   spcDec
09B0:A9 A0         438 spcloop   lda   #$A0          ; print a space for indenting
09B2:20 ED FD      439           jsr   cout
09B5:        09B5  440 spcDec    equ   *
09B5:CE D1 09      441           dec   PrntCnt       ; any more indenting?
09B8:10 F6   09B0  442           bpl   spcloop       ; yes - keep going
09BA:              443 *
09BA:A0 00         444           ldy   #0            ; get byte that has the length byte
09BC:B1 82         445           lda   (entPtr),y
09BE:29 0F         446           and   #$0F          ; get just the length
09C0:8D D1 09      447           sta   PrntCnt       ; put it into our counter
09C3:        09C3  448 PrntLoop  equ   *
09C3:C8            449           iny                 ; bump to the next char.
09C4:B1 82         450           lda   (entPtr),y    ; get next char
09C6:09 80         451           ora   #$80          ; COUT likes high bit set
09C8:20 ED FD      452           jsr   cout          ; print it
09CB:CE D1 09      453           dec   PrntCnt       ; printed all chars?
09CE:D0 F3   09C3  454           bne   PrntLoop      ; no - keep going
09D0:60            455           rts
09D1:              456 *
09D1:        0001  457 PrntCnt   ds    1             ; counter for printing
09D2:              458 *
09D2:              459 *******************************************************
09D2:              460 *
09D2:              461 * Some global variables
09D2:              462 *
09D2:        0001  463 Depth     ds    1             ; amount of recursion
09D3:        0002  464 ThisEntry ds    2             ; abs entry number

01 RECURSIVE.S     ProDOS Catalog Routine              27-AUG-88  16:20 PAGE 10
 
09D5:        0001  465 ThisBEntry ds   1             ; entry in this block
09D6:        0001  466 ThisBlock ds    1             ; block with dir
09D7:        0001  467 entryLen  ds    1             ; length of each directory entry
09D8:        0001  468 entPerBlk ds    1             ; entries per block
09D9:              469 *
09D9:              470 *******************************************************
09D9:              471 *
09D9:              472 * ProDOS command parameter blocks
09D9:              473 *
09D9:        09D9  474 OpenParms equ   *
09D9:03            475           db    3             ; number of parms
09DA:        0002  476 OpenName  ds    2             ; pointer to filename
09DC:00 00         477 ioBuf     dw    $0000         ; I/O buffer
09DE:        0001  478 oRefNum   ds    1             ; returned refnum
09DF:              479 *
09DF:        09DF  480 ReadParms equ   *
09DF:04            481           db    4             ; number of parms
09E0:        0001  482 rRefNum   ds    1             ; refnum from Open
09E1:F1 09         483           dw    buffer        ; pointer to buffer
09E3:00 02         484 reqAmt    dw    512           ; amount to read
09E5:        0002  485 retAmt    ds    2             ; amount actually read
09E7:              486 *
09E7:        09E7  487 CloseParms equ  *
09E7:01            488           db    1             ; number of parms
09E8:        0001  489 cRefNum   ds    1             ; refnum from Open
09E9:              490 *
09E9:        09E9  491 SetMParms equ   *
09E9:02            492           db    2             ; number of parms
09EA:        0001  493 sRefNum   ds    1             ; refnum from Open
09EB:        0003  494 Mark      ds    3             ; file position
09EE:              495 *
09EE:        09EE  496 GetPParms equ   *
09EE:01            497           db    1             ; number of parms
09EF:F1 0B         498           dw    nameBuffer    ; pointer to buffer
09F1:              499 *
09F1:        0200  500 buffer    ds    512           ; enough for whole block
0BF1:              501 *
0BF1:        0040  502 nameBuffer ds   64            ; space for directory name

01 SYMBOL TABLE    SORTED BY SYMBOL                    27-AUG-88  16:20 PAGE 11
 
 09F1 BUFFER         095B CHOPLOOP       0956 CHOPNAME         CC CLOSECMD      
 09E7 CLOSEPARMS     FDED COUT           09E8 CREFNUM        FD8E CROUT         
 09D2 DEPTH          0955 DESTPTR        09A5 DIRDONE          80 DIRNAME       
 084D DONE           09D8 ENTPERBLK        82 ENTPTR         09D7 ENTRYLEN      
 081E EXIT           0953 EXTCNT         0920 EXTENDNAME     0933 EXTLOOP       
 BEF5 GETBUFR        0968 GETNEXT          C7 GETPCMD        09EE GETPPARMS     
 09DC IOBUF          0845 ITSADIR        0831 LOOP           09EB MARK          
 BF00 MLI            0BF1 NAMEBUFFER     0848 NEXTENTRY        24 OENTBLK       
   25 OENTDIR          23 OENTLEN          C8 OPENCMD        0854 OPENDIR       
 0899 OPENDONE       09DA OPENNAME       09D9 OPENPARMS      09DE OREFNUM       
   00 OTYPE          09A7 PRINTENTRY     09D1 PRNTCNT        09C3 PRNTLOOP      
   CA READCMD        0829 READDIR1       081F READDIR        098A READNEXT      
 09DF READPARMS      08B0 RECURSDIR     ?09E3 REQAMT        ?09E5 RETAMT        
 09E0 RREFNUM          CE SETMCMD        09E9 SETMPARMS      0972 SKIP1         
 09B5 SPCDEC         09B0 SPCLOOP        0954 SRCPTR         09EA SREFNUM       
?0800 START          09D5 THISBENTRY     09D6 THISBLOCK      09D3 THISENTRY     
 08A1 VISITDIR       089A VISITFILE     
** SUCCESSFUL ASSEMBLY := NO ERRORS
** ASSEMBLER CREATED ON 15-JAN-84 21:28 
** TOTAL LINES ASSEMBLED   502 
** FREE SPACE PAGE COUNT   81 


Further Reference
o    ProDOS 8 Technical Reference Manual

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#18:    /RAM Memory Map

Revised by:    Matt Deatherage                "                 November 1988
Written by:    Pete McDoncld     "         "       "            December 1986

This Technical Note describes the block to actual oeoory location oarping of 
/RAM.
_____________________________________________________________________________

                Blocks     Address Range
            ______________________________
           |   $70-$7F   |   $E000-$EFFF  |
            ______________________________
           |   $68-$6F   |   $D000-$DFFF  |  (Bank 2)
            ______________________________
           |   $60-$67   |   $D000-$DFFF  |  (Bank 1)
            ______________________________
           |   $4E-$5C   |   $A200-$BFFF  |
            ______________________________
           |   $3D-$4C   |   $8200-$A1FF  |
            ______________________________
           |   $2C-$3B   |   $6200-$81FF  |
            ______________________________
           |   $1B-$2A   |   $4200-$61FF  |
            ______________________________
           |   $0A-$19   |   $2200-$41FF  |
            ______________________________

            ______________________________
           |   $5D-$5F   |   $1A00-$1FFF  |
            ______________________________
           |     $4D     |   $1800-$19FF  |
            ______________________________
           |     $3C     |   $1600-$17FF  |
            ______________________________
           |     $2B     |   $1400-$15FF  |
            ______________________________
           |     $1A     |   $1200-$13FF  |
            ______________________________
           |     $09     |   $1000-$11FF  |
            ______________________________
           |     $08     |   $2000-$21FF  |
            ______________________________
           |     $02     |   $0E00-$0FFF  |
            ______________________________
			
            ______________________________
           |     $03     |     Bitmap*    |
            ______________________________

Notes:
*     Synthesized.
1.    Blocks 0, 1, 4, 5, 6, and 7 do not exist.
2.    Block $7F contains the Reset, IRQ, and NMI vectors and is normally 
      marked as used.
3.    The memory from $0C00 - $0DFF is a general purpose buffer used by the 
      /RAM driver.


Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#19:    File Auxiliary Type Assignment

Revised by:    Matt Deatherage                                  November 1988
Written by:    Matt Deatherage                                       May 1988

This Technical Note describes file auxiliary type assignments.
_____________________________________________________________________________

The information in a ProDOS file auxiliary type field depends upon its primary 
file type.  For example, the auxiliary type field for a text file (TXT, $04) 
is defined as the record length of the file if it is a random-access file, or 
zero if it is a sequential file.  The auxiliary type field for an 
AppleWorks(TM) file contains information about the case of letters in the 
filename (see Apple II File Type Notes, File Types $19, $1A, and $1B).  The 
auxiliary type field for a binary file (BIN, $06) contains the loading address 
of the file, if one exists.

Auxiliary types are now used to extend the limit of 256 file types in ProDOS.  
Specific auxiliary types can be assigned to generic application file types.  
For example, if you need a file type for your word-processing program, Apple 
might assign you an auxiliary type for the generic file type of Apple II word 
processor file, if it is appropriate.

An application can determine if a given file belongs to it by checking the 
file type and the auxiliary type in the directory entry.  Other programming 
considerations include the following:

1.    If your program displays auxiliary type information, it should 
      include all auxiliary types, not just selected ones.  Try to 
      display the auxiliary type information stored in the directory 
      entry, just as you would display hex codes for file types for 
      which you do not have a more descriptive message to display.
2.    Programs should not store information in an undefined auxiliary 
      type field.  Storing the record length in a text file is fine, and 
      it is even encouraged, but storing the number of words in a text 
      file in that text file's auxiliary type field might cause problems 
      for those programs which expect to find a record length there.  
      Similarly, storing data in the auxiliary type field will cause 
      problems if your data matches an auxiliary type which is assigned.  
      To avoid these problems, only store defined items in a file's 
      auxiliary type field.  If you do not know of a definition for a 
      particular file type's associated auxiliary type, do not store 
      anything in its field.

To request a file type and auxiliary type, please send Apple II Developer 
Technical Support a description of your proposed file format, along with a 
justification for not using existing file and auxiliary types.  We will 
publish this information publicly, unless you specifically prohibit it, since 
we feel doing so enables the exchange of data for those applications who 
choose to support other file formats.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 16 Technical Reference
Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#20:    Mirrored Devices and SmartPort

Revised by:    Matt Deatherage                                  November 1988
Written by:    Matt Deatherage                                       May 1988

This Technical Note describes how ProDOS 8 reacts when more than two SmartPort 
devices are connected, how applications using direct device access should 
behave, and other related issues.  This Note supersedes Section 6.3.1 of the 
ProDOS 8 Technical Reference Manual.
_____________________________________________________________________________

Although SmartPort theoretically can handle up to 127 devices connected to a 
single interface (in practice, electrical considerations curtail this 
considerably), ProDOS 8 can handle only two devices per slot.  This is because 
ProDOS uses bit 7 of its unit_number is used to distinguish drives from each 
other, and a single bit cannot distinguish more than two devices.

When it boots, ProDOS checks each interface card (or firmware equivalent in 
the IIc or IIGS) for the ProDOS block-device signature bytes ($Cn01 = $20, 
$Cn03 = $00, and $Cn05 = $03), so it can install the appropriate device-driver 
address in the system global page.  If the signature bytes match, ProDOS then 
checks the SmartPort signature byte ($Cn07 = $00), and if that byte matches 
and the interface is in slot 5 (or located at $C500 in the IIc or IIGS), 
ProDOS does a SmartPort STATUS call to determine how many devices are 
connected to the interface.  If only one or two drives are connected to the 
interface, ProDOS installs its block-device entry point (the contents of $CnFF 
added to $Cn00) in the device-driver vector table, which starts at $BF10.  In 
this particular instance, ProDOS would put the vector at $BF1A for slot 5, 
drive 1, and if two drives were found, at $BF2A for slot 5, drive 2 .

If the interface is in slot 5 and more than two devices are connected, ProDOS 
copies the same block-device entry point that it uses for slot 5, drives 1 and 
2 in the device driver table entry for slot 2, drive 1, and if four drives are 
connected, for slot 2, drive 2.  Further in the boot process, if ProDOS finds 
the interface of a block device in slot 2 (not possible on a IIc), it replaces 
the vectors copied from slot 5 with the proper device-driver vectors for slot 
2; this is the reason mirroring is disabled if there is a ProDOS device in 
slot 2.  Note that non-ProDOS devices (i.e, serial cards and ports, etc.) do 
not have vectors installed in the ProDOS device-driver table, so they do not 
interfere with mirroring.

When ProDOS makes an MLI call with the unit_number of a mirrored device, it 
sets up the call to the device driver then goes through the vector in the 
device-driver table starting at $BF00.  When the block device driver (located 
on the interface card or in the firmware) gets this MLI call, it checks the 
unit number which is stored at $43 and verifies if the slot number (bits four, 
five, and six) is the same as that of the interface.  If it is not, the ProDOS 
block device driver of the interface realizes it is dealing with a mirrored 
device, internally adds three to the slot number and two to the drive number, 
then processes it, returning the desired information or data to ProDOS.

If an application must make direct device-driver calls (something which is 
not encouraged), it should first check devlst (starting at $BF32) to verify 
that the unit_number is from an active device.  In addition, the application 
should mask off or ignore the low nibble of entries in devlst and know that 
one less than the number of devices in the list is stored at $BF31 (devcnt).  
The application then should use the unit_number to get the proper device-
driver vector from the ProDOS global page; the application should not 
construct the vector itself, because this vector would be invalid for a 
mirrored device.

The following code fragment correctly illustrates this technique.  It is 
written in 6502 assembly language and assumes the unit_number is in the 
accumulator.

devcnt    equ    $BF31
devlst    equ    $BF32
devadr    equ    $BF10
devget    sta    unitno       ; store for later compare instruction
          ldx    devcnt       ; get count-1 from $BF31
devloop   lda    devlst,x     ; get entry in list
          and    #$F0         ; mask off low byte
devcomp   cmp    unitno       ; compare to the unit_number we filled in
          beq    goodnum      ;
          dex
          bpl    devloop      ; loop again if still less than $80
          bmi    badunitno    ; error: bad unit number
goodnum   lda    unitno       ; get good copy of unit_number
          lsr    a            ; divide it by 8
          lsr    a            ; (not sixteen because devadr entries are
          lsr    a            ; two bytes wide)
          tax
          lda    devadr,x     ; low byte of device driver address
          sta    addr
          lda    devadr+1,x   ; high byte of device driver address
          sta    addr+1
          rts
addr      dw     0            ; address will be filled in here by goodnum
unitno    dfb    0            ; unit number storage

Similarly, applications which construct firmware entry points from user input 
to "slot and drive" questions will not work with mirrored devices.  If an 
application wishes to issue firmware-specific calls to a device, it should 
look at the high byte of the device-driver table entry for that device to 
obtain the proper place to check firmware ID bytes.  In the sample code above, 
the high byte would be returned in addr+1.  For devices mirrored to slot 2 
from slot 5, this technique will return $C5, and ID bytes would then be 
checked (since they should always be checked before making device-specific 
calls) in the $C500 space.  Applications ignoring this technique will 
incorrectly check the $C200 space.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    ProDOS 8 Technical Note #21, Identifying ProDOS Devices
Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


ProDOS 8
#21:    Identifying ProDOS Devices

Written by:    Matt Deatherage & Dan Strnad                     November 1988

This Technical Note describes how to identify ProDOS devices and their 
characteristics given the ProDOS unit number.
_____________________________________________________________________________

There are various reasons why an application would want to identify ProDOS 
devices.  Although ProDOS itself takes great pains to treat all devices 
equally, it has internal drivers for two types of devices--Disk II drives and 
the /RAM drive provided on 128K or greater machines.  Because all devices 
really are not equal (i.e., some cannot format while others are read-only, 
etc.),.an developer may need to know how to identify a ProDOS device.

Although the question of how much identification is subjective for each 
developer, ProDOS 8 offers a fair level of identification; the only devices 
which cannot be conclusively identified are those devices with RAM-based 
drivers, and they could be anything.  The vast majority of ProDOS devices can 
be identified,however, so you could prompt the user to insert a disk in 
UniDisk 3.5 #2, instead of Slot 2, Drive 2, which could be confusing if the 
user has a IIc or IIGS.

Note that for the majority of applications, this level of identification is 
unnecessary.  Most applications simply prompt the user to insert a disk by its 
name, and the user can place it in any drive which is capable of working with 
the media of the disk.  You should avoid requiring a certain disk to be in a 
specific drive since doing so defeats much of the device-independence which 
gives ProDOS 8 its strength.

When you do need to identify a device (i.e., if you need to format media in a 
Disk II or /RAM device), however, the process is fairly straightforward.  This 
process consists of a series of tests, any one of which could end with a 
conclusive device identification.  It is not possible to look at a single ID 
byte to determine a particular device type.  You may determine rather quickly 
that a device is a SmartPort device, or you may go all the way through the 
procedure to identify a third-party network device.  For those developers who 
absolutely must identify devices, we present the following discussion.


Isn't There Some Kind of "ID Nibble?"

ProDOS 8 does not support an "ID nibble."  Section 5.2.4 of the ProDOS 8 
Technical Reference Manual states that the low nibble of each unit number in 
the device list "is a device identification:  0 = Disk II, 4 = Profile, $F = 
/RAM."

When ProDOS 8 finds a "smart" ProDOS block device while doing its search of 
the slots and ports, it copies the high nibble of $CnFE (where n is the slot 
number) into the low nibble of the unit number in the global page.  The low 
nibble then has the following definition:

    Bit 3:      Medium is removable
    Bit 2:      Device is interruptible
    Bit 1-0:    Number of volumes on the device (minus one)

As you can see, it is quite easy for the second definition to produce one of 
the original values (e.g., 0, 4, or $F) in the same nibble for completely 
different reasons.  You should ignore the low nibble in the unit number in the 
global page when identifying devices since the first definition is 
insufficient to uniquely identify devices and the second definition contains 
no information to specifically identify devices.  Once you do identify a 
ProDOS block device, however, you may look at $CnFE to obtain the information 
in the second definition above, as well as information on reading, writing, 
formatting, and status availability.

When identifying ProDOS devices, we start with a list of unit numbers for all 
currently installed disk devices.  As we progress through the identification 
process, we will identify some devices while we will not know about others 
until the end of the process.


Starting with the Unit Number

ProDOS unit numbers (unit_number) are bytes where the bits are arranged in the 
pattern DSSS0000, where D = 0 for drive one and D = 1 for drive two, SSS is a 
three-bit integer with values from one through seven indicating the device 
slot number (zero is not a valid slot number), and the low nibble is ignored.

To obtain a list of the unit numbers for all currently installed ProDOS disk 
devices, you can perform a ProDOS MLI ON_LINE call with a unit number of $00.  
This call returns a unit number and a volume name for every device in the 
device list.  ProDOS stores the length of the volume name in the low nibble of 
the unit number which ON_LINE returns; if an error occurs, the low nibble will 
contain $0 and the byte immediately following the unit"number will contain an 
error code.  For more information on the ON_LINE call, see section 4.4.6 of 
the ProDOS 8 Technical Reference Manual.  We will discuss the error codes in 
more"dgtail later in this Note.

To kdentify the devkces in the device"list, we need to know in which physical 
slot the hardware resides, so we can look at the slot I/O ROM space and check 
the device's identification bytes.  Note that the slot-number portion of the 
unit number does not always represent the physical slot of the device, rather, 
it sometimes represents the logical slot where you can find the address of the 
device's driver entry point in the ProDOS global page.  For example, if a 
SmartPort device interface in slot 5 has more than two connected devices, the 
third and fourth devices will be mapped to slot 2; this mapping gives these 
two devices unit numbers of $20 and $A0 respectively, but the device's driver 
entry point will still be in the $C5xx address space.

ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort, discusses this 
kind of mapping in detail.  It also presents a code example which gives you 
the correct device-driver entry point (from the global page) given the unit 
number as input.  We repeat this code example below for your benefit.  It 
assumes the unit_number is in the accumulator.

devcnt    equ    $BF31
devlst    equ    $BF32
devadr    equ    $BF10
devget    sta    unitno       ; store for later compare instruction
          ldx    devcnt       ; get count-1 from $BF31
devloop   lda    devlst,x     ; get entry in list
          and    #$F0         ; mask off low byte
devcomp   cmp    unitno       ; compare to the unit_number we filled in
          beq    goodnum      ;
          dex
          bpl    devloop      ; loop again if still less than $80
          bmi    badunitno    ; error: bad unit number
goodnum   lda    unitno       ; get good copy of unit_number
          lsr    a            ; divide it by 8
          lsr    a            ; (not sixteen because devadr entries are
          lsr    a            ; two bytes wide)
          tax
          lda    devadr,x     ; low byte of device driver address
          sta    addr
          lda    devadr+1,x   ; high byte of device driver address
          sta    addr+1
          rts
addr      dw     0            ; aldress will be(filled in
     (                        ; here by goodnum
unitno    dfb    0           (;(unit number storage

Warning:(   Attempting to construct the device-driver entry point from 
|hm unit(n}mber is(very langerou{.( Always use the technique 
presented above.


Network Volumes

AppleTalk volumes present a special problem to some developers since they 
appear as "phantom devices," or devices which do not always have a device 
driver installed in the ProDOS global page.  Fortunately, the ProDOS Filing 
Interface (PFI) to AppleTalk provides us with a way to identify network 
volumes through an MLI call.  The ProDOS Filing Interface call FIListSessions 
is used to retrieve a list of the current sessions being maintained through 
PFI and any volumes mounted for those sessions.  The following presents an 
example:

Network   JSR   $BF00         ;ProDOS MLI
          DFB   $42           ;AppleTalk command number
          DW    ParamAddr     ;Address of Parameter Table
          BCS   ERROR         ;error occurred

ParamAddr DFB   $00           ;Async Flag (0 means synchronous only)
                              ;note there is no parameter count
          DFB   $2F           ;command for FIListSessions
          DW    $0000         ;AppleTalk Result Code returned here
          DW    BufLength     ;length of the buffer supplied
          DW    BufPointer    ;low word of pointer to buffer
          DW    $0000         ;high word of pointer to buffer
                              ;(THIS WILL NOT BE ZERO IF THE BUFFER IS
                              ;NOT IN BANK ZERO!!!)
          DFB    $00          ;Number of entries returned here

If the FIListSessions call fails with a bad command error ($01), then 
AppleShare is not installed; therefore, there are no networks volumes mounted.  
If there is a network error, the accumulator will contain $88 (Network Error), 
and the result code in the parameter block will contain the specific error 
code.  The list of current sessions is placed into the buffer (at the address 
BufPointer in the example above), but if the buffer is not large enough to 
hold the list, it will retain the maximum number of current sessions possible 
and return an error with a result code of $0A0B (Buffer Too Small).  The 
buffer format is as follows:

SesnRef   DFB    $00          ;Sessions Reference number (result)
UnitNum   DFB    $00          ;Unit Number (result)
VolName   DS     28           ;28 byte space for Volume Name
                              ;(starts with a length byte)
VolumeID  DW     $0000        ;Volume ID (result)

This list is repeated for every volume mounted for each session (the number is 
placed into the last byte of the parameter list you passed to the ProDOS MLI).  
For example, if there are two volumes mounted for session one, then session 
one will be listed two times.  The UnitNum field contains the slot and drive 
number in unit-number format, and note that bit zero of this byte is set if 
the volume is a user volume (i.e., it contains a special "users" folder).  
This distinction is unimportant for identifying a ProDOS device as a network 
pseudo-device, but it is necessary for applications which need to know the 
location of the user volume.  Note that if you mount two servers or more with 
each having its own user volume, the user volume found first in the list 
(scanned top to bottom) returned by FIListSessions specifies the user volume 
that an application should use.  See the AppleShare Programmer's Guide for the 
Apple IIGS (available from the Apple Programmer's and Developer's Association 
(APDA)) for more information on programming for network volumes.

If you keep a list of all unit numbers returned by the ON_LINE call and mark 
each one "identified" as you identify it, keep in mind that the unit numbers 
returned by FIListSessions and ON_LINE have different low nibbles which should 
be masked off before you make any comparisons.

Note:    You should mark the network volumes as identified and not 
try to identify them further with the following methods.


What Slot is it Really In?

Once you have the address of the device driver's entry point and know that the 
device is not a network pseudo-device, you can determine in what physical slot 
the device resides.  If the high byte of the device driver's entry point is of 
the form $Cn, then n is the slot number of the device.  A SmartPort device 
mirrored to slot 2 will have a device driver address of $C5xx, giving 5 as the 
physical slot number.

If the high byte of the device driver entry point is not of the form $Cn, then 
there are three other possibilities:

o    The device is a Disk II with driver code inside ProDOS.
o    The device is either /RAM with driver code inside ProDOS or a third-party 
     auxiliary-slot RAM disk device with driver code installed somewhere in 
     memory.
o    The device is not a RAM disk but has a RAM-based device driver, like a 
     third-party network device.

Auxiliary-slot RAM disks are identified by convention.  Any device in slot 3, 
drive 2 (unit number $B0) is assumed to be an auxiliary-slot RAM disk since 
ProDOS 8 will not recognize any card which is not an 80-column card in slot 3 
(see ProDOS 8 Technical Note #15).  There is a chance that some other kind of 
device could be installed with unit number $B0, but it is not likely.

To identify various kinds of auxiliary-slot RAM disks, you must obtain the 
unit number from the ProDOS global page.  The list of unit numbers starts at 
$BF32 (DEVLST) and is preceded by the number of unit numbers minus one 
(DEVCNT, at $BF31).  You should search through this list until you find a unit 
number in the form $Bx; if the unit number is $B3, $B7, $BB, or $BF, you can 
assume the device to be an auxiliary-slot RAM disk which uses the auxiliary 
64K bank of memory present in a 128K Apple IIe or IIc, or a IIGS.  If the unit 
number is one of the four listed above, you must remove this device to safely 
access memory in the auxiliary 64K bank, but if the unit number is not one of 
the four listed above, you can assume the device to be an auxiliary-slot RAM 
disk which does not use the normal bank of auxiliary memory.  (Some third-
party auxiliary-slot cards contain more than one 64K auxiliary bank; the 
normal use of this memory is as a RAM disk.  If the RAM-based driver for this 
kind of card does not use the normal auxiliary 64K bank for storage, it should 
have a unit number other than one of the four listed above.)  If the unit 
number is not one of the four listed above, you may safely access the 
auxiliary bank of memory without first removing this device.

Section 5.2.2.3 of the ProDOS 8 Technical Reference Manual contains a routine 
which disconnects the appropriate RAM disk devices in slot 3, drive 2, without 
removing those drivers which do not use that bank, to allow use of the 
auxiliary 64K bank.

Note:    Previous information from Apple indicated that /RAM could be 
distinguished from third-party RAM disks by a driver address of 
$FF00.  Although the address has not changed, some third-party 
drivers may have addresses of $FF00 as well, although this is 
not supported.  /RAM always has a driver address of $FF00 and 
unit number $BF, although any third-party RAM disk could install 
itself with similar attributes.

For Disk II devices, the three-bit slot number portion of the unit_number will 
always be the physical slot number.  Disk II devices can never be mirrored to 
another slot (the Disk II driver does not support it); therefore, it will be 
in the physical slot represented in the unit number which ProDOS assigns when 
it boots.

If the high byte of the device driver's entry point is not of the form $Cn, 
then you should assume that the slot number is the value SSS in the unit 
number (this is equivalent to assuming the device is a Disk II) for the next 
step, which is checking the I/O space for identification bytes.


What to Do With the Slot Number

Once you have the slot number, you can look at the slot I/O ROM space to 
determine the kind of device it is.  As described in the ProDOS 8 Technical 
Reference Manual, ProDOS looks for the following ID bytes in ROM to determine 
if a ProDOS device is in a slot:

    $Cn01 = $20
    $Cn03 = $00
    $Cn05 = $03

If you use the slot number, n, you obtained above, and the three values listed 
above are not present, then the device has a RAM-based driver and cannot 
further be identified.

If the three values previously discussed are present, then examination of 
$CnFF will give more information.  If $CnFF = $00, the device is a Disk II.  
If $CnFF is any value other than $00 or $FF ($FF signifies a 13-sector Disk 
II, which ProDOS does not support), the device is a ProDOS block device.

For ProDOS block devices, the byte at $CnFE contains several flags which 
further identify the device; these flags are discussed in section 6.3.1 of the 
ProDOS 8 Technical Reference Manual.


SmartPort Devices

Many of Apple's ProDOS block devices follow the SmartPort firmware interface.  
Through SmartPort, you can further identify devices.  Existing SmartPort 
devices include SCSI hard disks, 3.5" disk drives and CD-ROM drives, with many 
more possible device types.

If $Cn07 = $00, then the device is a SmartPort device, and you can then make a 
SmartPort call to get more information about the device, including a device 
type and subtype.  The SmartPort entry point is three bytes beyond the ProDOS 
block device entry point, which you already determined above.  The method for 
making SmartPort calls is outlined in the Apple IIc Technical Reference Manual 
and the Apple IIGS Firmware Reference.

The most useful SmartPort call to make for device identification is the STATUS 
call with statcode = 3 for Return Device Information Block (DIB).  This call 
returns the ASCII name of the device, a device type and subtype, as well as 
the size of the device.  Some SmartPort device types and subtypes are listed 
in the above manuals, with a more complete list located in the Apple IIGS 
Firmware Reference.  A list containing SmartPort device types only is provided 
in SmartPort Technical Note #4, SmartPort Device Types.


RAM-Based Drivers

One fork of the identification tree comes to an end at this point.  If the 
high byte of the device driver entry point was not $Cn and the device was not 
/RAM, we assumed it was a Disk II and used the slot number portion of the unit 
number to examine the slot ROM space.  If the ROM space for that slot number 
does not match the three ProDOS block device ID bytes, it cannot be a Disk II.  
Having ruled out other possibilities, it must be a device installed after 
ProDOS finished building its device table.  Perhaps it is a third-party RAM 
disk driver or maybe a driver for an older card which does not match the 
ProDOS block device ID bytes.

Whatever the function of the driver, you can identify it no further.  It quite 
literally could be any kind of device at all, and with neither slot ROM space 
to identify nor a standard location to compare the device driver entry point 
against, the best you can do is consider it a "generic device" and go on.


But Is It Connected, and Can I Read From It?

Just because a ProDOS device is in the table does not mean it is ready to be 
used.  There is always the possibility that the drive has no media in it.  
Back in the beginning, we made an ON_LINE call with a unit number of $00.  If 
the volume name of a disk in that device could not be read, or another error 
occurred, ProDOS 8 would return the error code to us in the ON_LINE buffer 
immediately following the unit number.  Those errors possible include:

    $27    I/O error
    $28    No Device Connected
    $2B    Write Protected
    $2F    Device off-line
    $45    Volume directory not found
    $52    Not a ProDOS disk
    $55    Volume Control Block full
    $56    Bad buffer address
    $57    Duplicate volume on-line

Note that error $2F is not listed in the ProDOS 8 Technical Reference Manual.

By convention, we interpret I/O error to mean the disk in the drive is either 
damaged or blank (not formatted).  We interpret Device off-line to mean that 
there is no disk in the drive.  We interpret No Device Connected to mean the 
drive really does not exist (for example, asking for status on a second Disk 
II when only one is connected).

If no error occurred for a unit number in the ON_LINE call (the low nibble of 
the unit number is not zero), the volume name of the disk in the drive follows 
the unit number.


Further Reference
o    ProDOS 8 Technical Reference Manual
o    AppleShare Programmer's Guide for the Apple IIGS
o    ProDOS 8 Technical Note #15, How ProDOS 8 Treats Slot 3
o    ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort


Make REAL money with your website!

The entire AOH site is optimized to look best in Firefox® 2.0 on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2008 AOH
We do not send spam. If you have received spam bearing an artofhacking.com email address, please forward it with full headers to abuse@artofhacking.com.