💾 Archived View for mirrors.apple2.org.za › archive › apple.cabi.net › System › GSOS.P8.Anatomy › DI… captured on 2024-02-05 at 14:49:07.
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
Disk Devices Low-level communication with a block-structured data storage device like a 3.5-inch disk drive or a hard disk is managed by an assembly-language subroutine called a disk driver. (This name is conventional only - a disk driver may actually communicate with a block storage device that is not a disk drive.) We say "low level" because the disk driver is the subroutine every operating system command eventually calls to access the disk, and it is the disk driver that directly manipulates the 1/0 locations that control the operation of the drive. The important tasks conventional disk drivers perform are z Moving the disk's read/write head over any track on the disk z Identifying data blocks within each track z Reading and writing data blocks z Reading the write-protect (or other) status of the disk z Formatting the disk The driver for a 5.25-inch drive performs these tasks using several disk 1/0 locations for controlling the disk stepper motor, storing a byte on a disk, reading a byte from a disk, and sensing the write-protect status of the disk. Under ProDOS 8, it is relatively easy to add a custom disk driver (such as one for controlling a RAMdisk) to the system - it's just a matter of changing a few bytes in the system global page to tell ProDOS 8 where you've loaded the driver and what slot and drive numbers you want to assign to it. The only difficult part is deciding where to put the driver so that it won't be overwritten by applications. GS/OS has a more formal mechanism for adding disk drivers, but we do not discuss them here; GS/OS comes with drivers for all the disk drivers you're ever likely to need. If you do need to know about how to write CS/OS disk drivers, refer to GS/OS Reference, Volume 2. In this chapter, we investigate just how GS/OS and ProDOS 8 determine what disk devices are available and how they keep track of the disk drivers associated with each 287 of these devices. We also review the general characteristics of a ProDOS 8 disk and learn how to write one from scratch. HOW GS/OS AND PRODOS 8 KEEP TRACK OF DISK DEVICES When GS/OS and ProDOS 8 boot up, one of the first things they do is - many disk devices are connected to the system and how they may be ac example, through a card in a slot or a RAM-based driver. (GS/OS also character devices.) We see how these operating systems identify disk devices next section. GS/OS Device Scan When you boot GS/OS, it scans the IIcs system looking for both block-structure devices and character devices. When it identifies a device for which a driver the SYSTEM/DRIVERS/ subdirectory on the boot disk, it loads the driver memory and installs it. Apple currently provides drivers for 3.5- and 5.25-inch drives, SCSI drives, and the console (the standard keyboard input and output system). If no driver for the device exists on disk, CS/OS tries to generate in memory on the fly; it can generate character drivers for printer and modem and disk drivers for most SmartPort devices. The disk devices CS/OS cannot driver for are the 5.25-inch disk drive and the HD20SC SCSI hard disk. GS/OS assigns a unique device number and device name to each device it finds the system. It assigns device numbers consecutively, beginning with 1, and the names begin with a period and can be up to 31 characters long (for example, .,r and .APPLEDISK3.5). Unlike ProDOS 8, CS/OS does not use unit numbers are derived from slot and drive numbers) to identifl' disk devices. You can use GS/OS DInfo command to determine the names of all the devices in the system. ProDOS 8 Device Scan Table 7-1 lists all the system global page locations ProDOS 8 uses to manage devices. ProDOS 8 stores the number of active disk devices, less 1, in DEVCNT ($11F31)z the system global page. It stores the physical locations of the disk devices (that is, their slot and drive numbers) in encoded form in a 14-byte table beginning at DEVLST ($BF32). As Figure 7-1 shows, the high-order 4 bits of each entry in this table hold the drive and slot number in packed form, and the low-order 4 bits hold ani identification code unique to the type of disk device installed (5.25-inch drive, 3.S inch drive, HD20SC hard disk, and so on). You can also use the ProDOS 8 ON - LINE command to determine the slot and drive locations of all the disk drives in the system. 288 Disk Devices Table 7-1 ProDOS 8 global page areas used for disk drive identification Address Symbolic Name Description $BF10 DEVADR01 "No device connected" address $BF12 DEVADR11 Slot 1, drive 1 driver address $BF14 DEVADR21 Slot 2, drive 1 driver address $8F16 DEVADR31 Slot 3, drive 1 driver address $BF18 DEVADR41 Slot 4, drive 1 driver address $BF1A DEVADRS1 Slot 5, drive 1 driver address $BF1C DEVADR61 Slot 6, drive 1 driver address $BF1E DEVADR71 Slot 7, drive 1 driver address $8F20 DEVADR02 "No device connected" address $BF22 DEVADRI2 Slot 1, drive 2 driver address $8F24 DEVADR22 Slot 2, drive 2 driver address $BF26 DEVADR32 Slot 3, drive 2 driver address $BF28 DEVADR42 Slot 4, drive 2 driver address $BF2A DEVADR52 Slot 5, drive 2 driver address $BF2C DEVADR62 Slot 6, drive 2 driver address $8F2E DEVADR72 Slot 7, drive 2 driver address $8F30 DEVNUM Device code for the last device accessed $8F31 DEVCNT Number of active devices minus 1 $8F32 DEVLST Table of active disk device codes (14 entries in table) NOTE: The format of the entries in DEVLST and DEVNUM is the same as shown in Figure 7-1, except that the low-order 4 bits of DEVNUM are always 0. Figure 7-1 The format of DEVLST ($BF32) table entries Each byte in the 14-byte DEVLST table holds the slot, drive, and disk identification number in a special packed format: 7 6 5 4 3 2 1 0 DR SLOT DISK_ID where DR = 0 for a drive 1 device = 1 for a drive 2 device SLOT = 1-7 (slot number for the device) DISK - ID = $0 for a 5.25-inch disk drive = $B for a 3.5-inch disk drive = $F for the [RAM device = the high-order 4 bits stored at $CnFE if a disk controller adhering to the extended protocol is being used NOTE: The /RAM device is logically equivalent to a slot 3, drive 2 disk drive. Its DEVLST entry is $BF. How GS/OS and ProDOS 8 Keep Track of Disk Devices 289 Suppose you are using a two-drive Apple lIe with an extended 80-column teM installed in the auxiliary slot and a disk controller card installed in slot 6. Pr""" sets up DEVCNT and DEVLST as follows: DEVCNT ($8F31) DEVLST ($BF32) $02 <--- three devices $E0 slot 6, drive 2 $60 <--- slot 6, drive 1 $BF <--- slot 3, drive 2 (IRAN) $00 11 zero entries $00 ProDOS 8 reserves a 32-byte area beginning at $BF10 for use as a disk driver table. This table holds the addresses of the disk driver to be used for each of the possible slot and drive combinations and 2 impossible ones (slot 0, drive 1 and ' drive 2). The first part of the table, from $BI'10 to $BF1F, holds the addresses for eight drive 1 devices in ascending slot order (~7); the second part holds information for the eight drive 2 devices. Since a disk controller card cannot reside in slot 0 (a slot that doesn't even exist the Apple lIe, IIc, or 1Ics), ProDOS 8 uses the two slot 0 entries in the disk vector table for a special purpose: to hold the address of the subroutine that MLI error $28 if ProDOS 8 calls it. This is the code for the "no device connec error. If the vector table entry for a given slot and drive combination is this at' ProDOS 8 has not assigned a disk device to that slot and drive. The six most common entries in the disk driver vector table are as follows: $D000 disk driver for a standard 5.25-inch disk drive (in bank-switched RAM $FF00 disk driver for the [RAM RAMdisk volume (in bank-switched I'lAfl) $DEAC address of "no device connected" error subroutine (in bank-swltch~ RAM) $Cn0A UniDisk 3.5 and Apple IIcs SmartPort (n = slot number of the controller card) $Cn4E Apple II Memory Expansion card (n = slot number of the memory card) The first three addresses are those used by ProDOS 8 version 1.7 only. (The others are fixed in ROM on firmware or controller cards.) They may change when Apple releases later versions of ProDOS 8. 290 Disk DevicesHOW GS/OS AND PRODOS 8 IDENTI~ DISK DEVICES To connect a disk device to an Apple II, you generally attach it to a disk controller card located in a peripheral expansion slot. (The Ilc and Ilcs both have built-in disk controllers, so no card is necessary.) This card is responsible for booting the disk and, in some cases, for transferring data between the Apple and the disk medium. A controller card holds a program in ROM that occupies the address space from $Cn00 to ~CnFF (where n is the slot number) and, sometimes, from $C800 to $CFFF. For standard 5.25-inch disk controllers, this program is capable of only transferring a short loader program from the disk medium into 11AM and executing it; this loader then reads in the rest of the disk operating system from disk. (This is where the term booting comes from: The operating system picks itself up by its own bootstraps.) Other controllers may contain code that performs much more sophisticated tasks, such as reading or writing any block on the disk, doing status checks, and formatting a disk. Intelligent controllers with these capabilities are used with 3.5-inch disks and hard disks. Apple currently uses an intelligent controller called a SmartPort for 3.5-inch drives and RAMdisk memory cards. (A SmartPort is built in to the II&s and newer models of the Ilc.) When ProDOS 8 or CS/OS first starts up, it examines each slot (beginning with 7 and working down to 1) to determine whether a controller card for a disklike device is present. A controller card contains the following unique pattern of bytes in its ROM (n is the slot number): $Cn0l $20 $Cn03 $00 $Cnos $03 The value of the byte stored at $Cn07 is also important. If the three identification bytes are present and location $Cn07 contains $3C, and if the controller is in a higher-numbered slot than any other disk controller, the original Apple II system Monitor program in ROM (the one in the II Plus or the original lIe) automatically boots the disk in the drive when you turn the system on. Unfortunately, $Cn07 cannot contain $3C in the ROM of a controller for a disk device other than a 5.25-inch disk drive because the Apple Pascal operating system erroneously believes any such device is a 5.25-inch disk drive. As a result, it is not possible to automatically boot from a hard disk or a 3.5-inch disk when using a system with the original Monitor program. You can automatically boot a non-5.25-inch disk device'if you have an Apple Ilcs or an enhanced Apple lIe. This is because the system fi1onitor in these computers identifies a bootable disk drive by the presence of the first 3 identification bytes only. If you want to know if the disk controller is a SmartPort (perhaps so that you can take advantage of the special SmartPort commands described later in this chapter), check location $Cn07. If it contains $00, it is a SmartPort. How GS/OS and ProDOS 8 Identijy Disk Devices 291 When ProDOS 8 or CS/OS finds the 3 identification bytes, it looks at the stored at $CnFF to determine the exact type of controller it has found. If contains $00, ProDOS 8 and CS/OS consider the card a 5.25-inch disk controller standard 16-sector-per-track ROMs. In this case, ProDOS 8 places the a device code in the DEVLST table and the address of the internal 5.25-inch device driver in the ProDOS 8 disk driver vector table. Note that it actually two entries in each tahle since each 5.25-inch disk controller can have two drives volumes) attached to it. (They are referred to as drive 1 and drive 2.) The disk itself ultimately determines if there is actually a drive 2 device attached and "device not connected" error code if an attempt is made to access it and it is not If $CnFF contains $FF, CS/OS and ProDOS 8 consider the card a 5.25-inch controller with 13-sector-per-track ItOMs. (This was the disk formatting scheme-'- by Apple's original 5.25-inch drive controller.) CS/OS and ProDOS 8 do not this type of controller card and so ignore it. If $CnFF contains any other value, GS/OS and ProDOS 8 assume the controller has a device driver entry point located in ROM at $CnXX, where XX is value stored at $CnFF. If bits 0 and 1 of the byte stored at $CnFE are both I describe the meaning of these bits in the next section), ProDOS 8 stores this in the device driver vector table and adds an appropriate device code to DEVL (The low-order 4 bits of the DEVLST entry are set equal to the high-order 4 bits the byte at $CnFE.) If one, or both, of bits 0 and 1 of $CnFE are 0, CS/OS ProDOS 8 ignore the disk controller. ProDOS 8 identifies three special "disk" devices in quite a different way. If it running on an Apple lIe with an extended 80-column card (the one with 64K auxiliary 11AM on it), or on an Apple IIc or IIcs, ProDOS 8 installs a special device, called a 11AMdisk, as the slot 3, drive 2 disk device. The medium for this disk is the 64K auxiliary memory space on the lIe, IIc, or IIcs, and disk 1/0 operations simply involve the movement of data blocks between auxiliary and main memory. The volume name for this 11AMdisk is always 111AM. GS/OS and ProDOS 8 create another type of 11AMdisk using memory on the Apple IIcs Memory Expansion card (or equivalent) if the Control Panel Minimum 11AM Disk Size parameter is not set to zero. This 11AMdisk is called 111AM5. The third special device, again available on the IIcs only, is a ROMdisk. Although Apple's memory card doesn't support ROMdisk memory, several independent suppliers have cards that do. Despite the name ROMdisk, the memory for the disk could also be in battery backed-up static or dynamic 11AM, EEPROM, or EPItOM. EXTENDED PROTOCOL FOR DISK CONTROLLER CARDS Apple has also defined a special extended controller card ROM protocol that manu- facturers of disk devices and disk controller cards must adhere to if their devices are to work properly with CS/OS and ProDOS 8. (The 5.25-inch disk controllers do not actually follow this protocol and are handled as special cases by GS/OS and ProDOS 292 Disk Devices 8.) This protocol defines the use of 4 bytes in the controller card ROM space as follows (n is the slot number of the card): z $CnFC and $CnFD. The total number of blocks on the volume is stored here (low-order byte first). This information is for the benefit of formatting programs that also initialize the volume directory and volume bit map on disk. The controller for the old 5-megabyte ProFile hard disk has the number $2600 (9728) stored here. If the number is $0000 (as it is for most controller cards), you must send a status request to the disk driver to determine the volume size; the number of blocks comes back in the X register (low) and Y register (high). We see how to make status requests in the next section. z $CnFE. This is the device characteristics byte. Each bit holds miscellaneous information about the device: bit 7 1 = the disk medium is removable bit 6 1 = the device is interruptible bits 5,4 The number of drives (or volumes) on the device (0-3). An even value (0 or 2) indicates one drive; an odd value (1 or 3) indicates two drives. bit 3 1 = the device driver supports format bit 2 1 = the device driver supports write bit 1 1 = the device driver supports read bit 0 1 = the device driver supports status The controller for the UniDisk 3.5 has the value $BF stored at $CnFE. This means the disk medium is removable (bit 7 = 1); the UniDisk 3.5 is not interruptible (bit 6 = 0); two volumes are supported (bits 5,4 = 11); and the device driver for the UniDisk 3.5, located in ROM on the controller card, supports format (bit 3 = 1), write (bit 2 = 1), read (bit 1 = 1), and status (bit 0 = 1) operations. z $CnFF. This byte contains the offset (from $Cn00) of the address of the ProDOS 8 disk driver for this device. If the byte at $CnFE indicates that the device can be read from and its status can be read (that is, bits 0 and 1 of the byte stored at $CnFE are both 1), the driver address is stored in the "drive 1" portion of the device driver vector table in the ProDOS 8 global page when ProDOS 8 is first booted. If the byte at $CnFE indicates that two drives are attached to the controller, the address of the device driver is also stored in the "drive 2" portion of the table unless ProDOS 8 is able to determine that a second drive is not actually connected. After the vector table is updated, bits ~7 of the byte stored at $CnFE are stored in the low-order 4 bits of the DEVLST entry for the device. The controller for the UniDisk 3.5 has the value $0A stored at $CnFF, and its DEVLST entry is of the form nB, where n is the controller slot number. This means the address of the disk driver is $Cn0A. Extended Protocol for Disk Controller Cards 293 Special Cases $CnFF contains $00 for a 16-sector 5.25-inch disk controller and $FF for a 1 5.25-inch disk controller. In these situations, GS/OS and ProDOS 8 .. special meaning to the values stored at $CnFC, $CnFD, and $CnFE. If ProDOS 8 finds a 16-sector controller, it assumes the disk medium is a volume of 280 blocks and uses its own internal disk driver to communicate - CS/OS uses a similar driver it loads from the SYSTEM/DRIVERS/ su.. CS/OS and ProDOS 8 ignore the older 13-sectorS.2S-inch disk controller. COMMUNICATING WITH A PRODOS 8 DISK DRIVER Just before ProDOS 8 calls a disk driver subroutine, it sets up four parameters th microprocessor's page zero area that serve to inform the disk driver of the operation to be performed. These parameters define the tye of disk operation write, format, or check device status), the slot and drive number of the disk device, address of the 512-byte (one block) data transfer buffer to be used, and the block The four parameters are stored in locations $42 to $47 and have the loll meanings: z COMMAND ($42). This location holds the command code for the disk to be performed. Four codes are defined: 0 Check device status. On return, the carry flag is clear and the accumulator is zero if the device is ready to accept read and write commands. Moreover, the number of blocks on the disk is in the X register (low) and Y register (high) but only if the device's controller ROM adheres to the 1 2 3 extended ProDOS 8 protocol (remember that 5.25-inch disk controllers do not). If the device is not ready to accept read and write commands, the carry flag is set, and the accumulator contains an MLI error code. The standard drivers for 3.5- and 5.25-inch drives return an error code on a status request if the disk medium is write-protected (error $28) or no disk is in the drive (error $2F). Read one block from the disk. Write one block to the disk. Format the disk. When you format a disk, special address marks are set up to allow each sector to be identified by the disk driver. Generally, the formatting process does not also set up the boot record, volume directory, and bit map blocks; this must be done by making write requests. (The driver for /RAM is an exception.) The format request is actually not supported by the standard 294 Disk Devices 5.25-inch device driver because of space limitations; instead, a separate utility program (such as Filer on the ProDOS 8 master disk) must be used to format a diskette or hard disk and to lay out the boot record, volume directory, and bit map. The source code for the standard diskette formatting subroutines (called F0RMATTER) can also be licensed from Apple for use in other formatting programs. The format request is supported by the /RAM driver and the 3.5-inch disk driver. z SLOT-DRIVE ($43). These locations hold the drive and slot numbers of the disk device to be accessed, in the following format: bit 7 bits 4,5,6 bits 0,1,2,3 0 (drive 1) or 1 (drive 2) slot number (1-7) always 0 For example, a slot 6, drive 2 device would be represented as 11100000 ($E0). z BUFFER - I11'R ($4~$45). These locations hold the address (low-order byte first) of the start of a 512-byte area of memory that holds the image of the block to be written to the disk (COMMAND = 2) or that will hold the block read from the disk (COMMAND = 1). BUFFER PTR should also be properly set up before malcing a format request (COMMAND = 3) because the formatting subroutines for some disk devices (like /11AM) may use the buffer area for temporary data storage. BLOCK - NUM ($4~$47). These locations hold the number (low-order byte first) of the block on the disk to be written to (COMMAND=2) or read from (COMMAND = 1). The disk driver performs the 1/0 operation dictated by these parameters and then returns control to the caller. If no error occurred, the carry flag is clear, and the accumulator is zero. Errors can occur, of course, when ProDOS 8 communicates with a disk device. The disk drivers flag error conditions in the standard MLI way: by setting the carry flag and placing an appropriate MLI error code in the accumulator. Table 7-2 shows the error codes and conditions supported by the ProDOS 8 disk driver for standard 5.25-inch disk drives. Any other properly implemented disk driver will identify and report these error conditions in the same way. THE SMARTPORT CONTROLLER A SmartPort is the intelligent device controller Apple now uses to interface to all its high-capacity disk drives, including the UniDisk 3.5, Apple 3.5 Drive, and HD20SC SCSI hard disk. The SmartPort firmware can handle up to 127 devices chained The SmartPort Controller 295 Table 7-2 ProDOS 8 disk driver error codes $28 $2B $2F No disk device is connected The medium is write-protected The device is off-line together to the same SmartPort, but the Apple power supply gives out well then - for the SmartPort on the II&s, for example, Apple recommends c' more than four 3.5-inch drives. As we mentioned earlier in this chapter, the SmartPort firmware has the same basic identification bytes as any other ProDOS-compatible disk controller. A location $Cn07 serves to uniquely identify the controller as a SmartPort, however, SmartPort ID type byte at $CnFB gives you a little more information about SmartPort: bit 0 1 = supports RAMdisk card bit 1 1 = supports SCSI devices bit 2 [reserved] bit 3 [reserved] bit 4 [reserved] bitS [reserved] bit 6 [reserved] bit 7 1 = supports extended commands The SmartPort assigns a unique unit number (from $01 to $7F) to each L.. connected to it. The numbers it assigns are consecutive, starting with $01. SmartPort controller itself is unit number $00.) Programs use the unit number identify the device a SmartPort command is directed to. In general, the SmartPort assigns unit numbers to devices in the order they in the chain of devices. But on the II&s, the SmartPort considers any BOMdisk /11AM5 11AMdisk (the 11AMdisk you set up with the Control Panel) in the system to L part of the SmartPort chain and assigns unit numbers to them first. To complic matters further, if the startup device (set using the Control Panel) is a SmartPort device, the SmartPort rearranges unit numbers to ensure the startup device has a unit number of $01. The only safe way to determine which device corresponds to a given unit nutnber is to use the SmartPort's Status command (see below). Many ProDOS 8 commands use slot and drive parameters to identify a disk device, so ProDOS 8 automatically assigns slot and drive combinations to SmartPort unit numbers when it first boots up. Assuming the SmartPort is in slot 5, ProDOS 8 assigns 296 Disk Devicesthe first four SmartPort devices to slot 5, drive 1; slot 5, drive 2; slot 2, drive 1; and slot 2, drive 2. It ignores any other devices that may be connected to the SmartPort. The phantoming of the third and fourth devices to slot 2 is necessary because ProDOS 8 has space for only two drives per slot in its disk driver vector table. Using SmartPort Commands The SmartPort firmware provides several commands a program can use to communi- cate with a disk device. Under ProDOS 8, you won't have to use them for common types of disk operations because you can use the disk driver commands described in the previous section instead. Under GS/OS, you can probably get by with the DInfo, DRead, DWrite, DStatus, and DControl commands. You will have to use SmartPort commands to obtain extended status information and to perform special control operations, however. To use a SmartPort command, you must first determine the dispatch address of the command interpreter. This address is always 3 bytes past the standard ProDOS 8 device driver entry point, so its offset into page $Cn00 is the value stored at $CnFF plus 3. You call a standard SmartPort command much as you call a ProDOS 8 MLI command: JSR DISPATCH DISPATCH = $Cn00+($CnFF)+3 DFB CMONUM ;SmartPort command number DA PARM_BLK ;Pointer to Smart Port parameters 8CS ERROR ;Carry set if error occurred where DISPATCH is the SmartPort dispatch address, CMDNUM is the SmartPort command number, and PARM - BLK is a command-specific parameter block. (If CS/OS is active on a IIcs, you must call the SmartPort dispatcher in emulation mode with code that resides in bank $00.) If an error occurs, the carry flag is set, and the accumulator contains the error code. If the operation was successful, the carry flag is clear, and the accumulator is zero. If bit 7 of the SmartPort ID type byte at $CnFB is 1 (and it is for the IIcs SmartPort), the SmartPort also supports extended SmartPort commands. The com- mand number for an extended command is the same as the number for the corre- sponding standard command except that bit 6 is set to 1. That means, for example, if the standard command number is $01, the extended command number is $41. You call extended commands just like standard commands except that the pointer to the parameter block contains a long address (4 bytes) rather than a short address (2 bytes). This permits access to a parameter block located anywhere in the IIcs's 16Mb memory space. The other difference between a standard and extended command is the strncture of the parameter block for the command, as we see below. The SmartPort Controller 297 Important: The IIcs SmartPort clobbers several locations in the caller's direct page (IIcs ROM version 01) or true zero page (original II&s ROM) you call a SmartPort command. The affected locations are $57 through these locations are important to your application, save them before a call and restore them afterward. All SmartPorts support a standard set of commands so that ProDOS 8 or GS/O5 communicate with it properly. The ones you probably will never use in an I: are ReadBlock, WriteBlock, Format, and Init (you can use ProDOS 8 disk dri GS/OS commands instead) as well as Open, Close, Read, and Write (appropriate character devices only). Let's now take a close look at the two remaining Status and Control. Status Command The Status command is for determining the status of any device in the chain or the SmartPort controller itself. Its command number is $00 (standard) or (extended), and the standard parameter block looks like this: parameter count (byte, always $03) unit number (byte, from $00 to $7E) status list pointer (low byte) status list pointer (high byte) status code (byte, from $00 to $FF) The extended parameter block uses a 4-byte pointer to the status list instead (low-ord~ bytes first). You must reserve space for the status list before calling the Status command There are four possible values for the status code byte: $00 return device status "'I, ',':+',,',7, ~~, ~.trn'I. h'l.nck. $02 return newline status $03 return device information block Of these, you probably won't use code $01 or $02 very often. Code $01 returns a device.dependent control block, up to 256 bytes long, preceded by a length byte; a length byte of $00 means the block is 256 bytes long. Code $02 is for character devices only. Code $00 (return device status) returns 4 or 5 bffes in the status list depend- ing on whether a standard or extended call is made. The first bffe is a general device status byte: 298 Disk Devices bit 0 1 = disk switched (block device only) or 1 = device is open (character device only) bit 1 1 = device is interrupting bit 2 1 = medium is write-protected (block device only) bit 3 1 = device allows formatting bit 4 1 = a disk is in the drive bit 5 1 = device allows reading bit 6 1 = device allows writing bit 7 1 = block device 0 = character device Note that the disk-switched bit is 1 if a disk has been ejected and another disk (perhaps the same one) has been inserted since the last status check. But this bit is significant only if the device supports disk-switched errors; it does if bit 6 of the subtype byte returned by the code $03 status command is 1 (see below). Of Apple's SmartPort devices, only the Apple 3.5 Drive for the IIcs supports these types of errors. (The UniDisk 3.5 does not.) The next 3 bytes (standard call) or 4 bytes (extended call) hold the size of the device in blocks. These bytes are zero if the device is a character device. The SmartPort handles a Status call differently if the unit number is $00. In this case, it returns an 8-byte status list describing the status of the SmartPort controller itself: byte 0 number of devices the SmartPort controls byte 1 interrupt status (no interrupt if bit 6 is set) byte 2 manufacturer of driver: $00 = unknown $01 = Apple $02 = third-party driver Bytes 3 through 7 are reserved. Code $03 (return device information block) returns more detailed status informa- tion in the status list. The form of the list after a standard call is as follows: device status (byte) block size (low byte) block size (medium byte) block size (high byte) ID string length (byte) ID string (16 bytes) device type (byte) device subtype (byte) version (2 bytes) The SmartPort Controller 299 For an extended call, the block size field occupies 4 bytes instead of 3. The device status and block size bytes are the same as those returned by a code $00 call. The ID string is a sequence of up to 16 standard ASCII cL high-order bit of each character is 0) representing the name of the <' 16-character string space is padded with spaces if necessary. The device type byte tells you the general nature of the device you're dealing The currently defined values are as follows: $00 Memory expansion card RAMdisk $01 3.5-inch disk drive $02 ProFile-type hard disk $03 Generic SCSI hard disk $04 R0Mdisk $05 SCSI CD-R0M $06 SCSI tape or other SCSI sequential device SCSI hard disk [reserved] SCSI printer 5.25-inch disk drive [reserved] [reserved] Printer Clock Modem $07 $08 $09 $0A $0B $0C $00 $0E $0F The subtype byte indicates some of the characteristics of the device: bit 7 1 = supports extended SmartPort commands bit 6 1 = supports disk-switched errors bit 5 1 = nonremovable medium The other 5 bits are reserved. Version is a word (low-order byte first) describing the version number of SmartPort device driver. Control Command The Control command sends control information to a device. Its command number $04 (standard) or $44 (extended), and the standard parameter block looks like this: parameter count (byte, always $03) unit number (byte, from $00 to $7E) control list pointer (low byte) control list pointer (high byte) control code (byte, from $00 to $FF) 300 Disk Devices The extended parameter block uses a 4-byte pointer to the control list instead (low-order bytes first). The Control command understands five general control codes, only one of which (eject medium) is particularly useful to most applications: $00 (device reset), $01 (set device control block), $02 (set newline status), $03 (service device interrupt), and $04 (eject medium). Device-specific control codes are numbered $05 and above. The most useful control code for most applications is the one that causes a 3.5-inch disk to eject automatically. For the UniDisk 3.5 SmartPort card and the internal IIcs SmartPort, the eject control code is $04, and the control list contains two $00 bytes. (For a summary of other device-specific control codes, see Chapter 7 of Apple tics Firmware Reference.) Remember to use the eject command with 3.5-inch drives only. You can easily check whether you're dealing with a 3.5-inch drive by using the Status command. If you are, the device type byte is $01, the block size is $000640, and the ID string is DISK 3.5. If you need to be convinced to do a Status check first, keep in mind that revisions A and B of the SCSI card (a SmartPort device) for Apple's HD205C hard disk use a control code of $04 to format the disk! That's not an operation you want to perform accidentally. (For revision C of the SCSI card, the $04 code is the eject code.) THE PRODOS 8 RAMDISK: THE /RAM VOLUME We saw earlier that ProDOS 8 automatically installs a special 11AMdisk driver if you are using an Apple IIcs, Apple IIc, or Apple lIe with an extended 8O-column text card and creates a special volume called /RAM. (Apple II Plus users are out of luck.) All these systems have 64K of auxiliary memory that maps to addresses in exactly the same way as the standard 64K of main 11AM memory usually used for program and data storage. In this auxiliary memory, the 11AMdisk driver stores the volume direc- tory, volume bit map, and file blocks. Figure 7-2 shows a map of the usage of auxiliary memory by /RAM. Since no slow-moving mechanical parts are used to perform "disk" operations (all 1/0 operations simply involve block moves from one part of memory to another), the 11AMdisk responds much more quickly than a conventional disk drive. But its contents are tempo- rary, so you must be careful to transfer any files from it to a permanent disk medium before turning off the Apple or rebooting ProDOS 8, or you will lose all of your data. Characteristics of the /RAM Volume When ProDOS 8 initializes the /11AM volume, it allocates only one volume directory block (block 2; recall that standard disks use four directory blocks). This means there is room for only 12 entries in the volume directory, not the usual 51. If files are created inside subdirectories, however, you can store as many files as will fit on the volume. When ProDOS 8 first initializes the /11AM volume, 119 blocks are available for file storage. (They are numbered from 8 to 126.) Since a 64K space is normally capable of holding 128 512-byte blocks, you might be wondering about the "missing" 9 blocks. The Pro DOS 8 RAI$tdisk: The 111AM Volume 301 Figure 7-2 A map of auxiliary memory usage on the Apple lIe, lIe, and IIcs with ProDOS 8 active Auxiliary bank-switched RAM $EO00 $DO00 ~BFrF Auxiliary memory $Ocoo 0 00 0 00 -0400 0200 0100 0000 Bank vectors $FEO0..$FFF9 not used Bank2 /RAM block storage area (blocks 2,3,8.. I 26) Unused but reserved On llc only: $800..$87F is serial input buffer $880..$8FF is keyboard buffer Video RAM (80-column mode) Part of /RAM device driver used by /RAM device driver Two of these are relatively easy to track down: One is used for the volume directory (block 2) and another for the volume bit map (block 3). There is no room in auxiliary memory for the other seven blocks (0, 1, ~7, and 127) because space must be reserved to support the /RAM disk driver itself ($000~$03FF), the 80-column text screen ($0400-$07FF), the keyboard and serial input buffers on the Apple lIe ($080~$08FF), and the auxiliary memory interrupt vectors ($FFFA-$FFFF). Thus these seven blocks are marked as "in use" in the 111AM volume bit map. The areas of auxiliary memory that the 111AM volume or its driver does not use are as follows: 302 Disk Devices $0~$3B, $4~$FF $090~$0BFF $FE00-$FFF9 Despite the apparent availability of these areas, they should be considered reserved for future use by later versions of ProDOS 8 and must not be used by nonsystem software. The first 8K of memory allocated for use by files stored in 1RAM maps to locations $200~$3FFF in auxiliary memory. This same space is used whenever you activate page 1 of the double-width high-resolution graphics display mode available on the IIcs, IIc, or lIe. If you are going to use this graphics mode while 111AM is active, you must first prevent any meaningful program from being stored at these locations. The easiest way to do this is to ensure that the first file saved to 111AM is a dummy file exactly 8K bytes long. You can do this by entering the following command from Applesoft command mode: BSAVE /RAM/OUMMY,A$2000,E$3FFF The second 8K area used to store files in 111AM is mapped to locations $4000-$5FFF, the same area used as the second page of double-width high-resolution graphics. You can protect this page by saving another dummy file that is 8K long. Removing and Reinstalling 111AM You may want your application to use the auxiliary memory area for purposes other than as a convenient file-storage device. Other common uses for auxiliary memory are as a data buffer for a printer spooler or as an input buffer for a communications program. But before you start overwriting the BAM volume with such data, you must remove the 111AM volume from the system in an orderly manner. If you don't, the system could crash when ProDOS 8 tries to interpret what you've written to auxiliary memory as directory, bit map, or file information. It's actually quite simple to remove the 111AM device from the system. 1. Examine MACHID ($BF98) to see if you're running in a 128K system. (Bits 4 and 5 of MACHID will both be 1 if you are.) 111AM can exist in only a 128K system. 2. Check that 111AM has not already been removed by locating the $BF device code (slot 3, drive 2) among the active entries in the DEVLST table. You should also check for any entry of the form $BX, where X = $3, $7, or $B; by convention, these slot 3, drive 2 devices, though not equivalent to 111AM, will also use the first bank of auxiliary memory. (Cards such as RamWorks III and MultiRAM have several banks of auxiliary memory available.) The actual $BX byte stored in DE""L8T must be saved if you later want to reinstall the 111AM device. The ProDOS 8 RAMdisk: The 111AM Volume 303 3. Remove the $BX entry from the DE"'LST table by moving higher-addressed active entries down one position (starting with the lowest-addressed one). 4. Replace the slot 3, drive 2 entry in the device vector table (at $BF2~$BF27) with the address stored at the slot 0, drive 1 entry (at $BF1~$BF11). (This will be the address of the subroutine that generates a "no device connected" error condition.) The original slot 3, drive 2 entry must be saved if you later want to reinstall the 1RAM device. 5. Decrement DEVCNT ($BF31). 6. Make an ON - LINE call with unit - num set to $B0. This frees up an internal buffer so that you can have more disk volumes active at once. After you perform these steps, the 1RAM device disappears from ProDOS 8, and auxiliary memory can be safely used for other purposes. When your application ends, it should reinstall 111AM. Do this by performing the following steps: 1. As a precaution, veri~ that you have not already reinstalled 111AM by checlcing for a slot 3, drive 2 device code in DEVLST. 2. Restore the original slot 3, drive 2 device vector that you saved before 111AM was disconnected. 3. Move each active entry in DEVLST to the next higher memory location (starting with the highest-addressed entry), and then store the 111AM device code (that you saved before 111AM was disconnected) at the first entry in the list (at $BF32). 4. Increment DEVCNT ($BF31). 5. Initialize the volume directory and volume bit map of the 111AM device by setting up the disk driver parameters for a format request ($42 = 3, $43 = $B0, $4~ $45 = 512-byte buffer address) and then calling the disk driver. Since the 111AM device driver resides in bank 1 of bank-switched RAM, you must enable that bank by reading $C08B twice in succession before making the call. When the call ends, reenable the Applesoft and motherboard ROMs by reading $C082. Here is a subroutine that performs all these chores: LDA #3 Format code STA $42 LDA #$B0 ;Unit number code STA $43 LDA $73 ;Set buffer address STA $44 ; to HIMEM LDA $74 STA $45 LDA $C08B Read/write enable bank1 304 Disk DevicesLDA $C08B ; (where the driver is) JSR T0RAM LDA $C082 ;Reenable Applesoft R0Ms RTS T0RAM JMP ($BF26) ;Call the /RAM driver After you reinstall 111AM like this, it is once again available for use as a file-storage device. WRITING A PRODOS 8 DISK DRIVER The best way to learn about disk drivers and how ProDOS 8 installs them is to actually write one. In this section, we do just that by creating a driver for an 8K version of 111AM called 1RAM8. It is suitable for use in an Applesoft programming environment and can be used by all ProDOS 8 users (unlike 111AM, which is not available to Apple II Plus users). The BAMdisk driver itself resides in page three, and the "disk" storage space it uses is located from $0800 to $27FF. We ensure that Applesoft programs do not conflict with the RAMdisk storage space by setting the Applesoft start-of-program pointer at $67-$68 to $2801 and then initializing the other Applesoft pointers and data areas by executing a NEW command. Before we begin to create the disk driver, let's outline the steps to follow to remedy the Applesoft conflict, bind the driver into ProDOS 8, and then initialize the RAM-- disk. This is really a five-step process. The first step in the procedure is to adjust the Applesoft pointers so that when you enter or load BASIC programs, they will not overwrite the 111AM8 volume: LDA #$01 ;Starting address (low) STA $67 ;Program pointer (low) IDA #$28 Starting address (high) STA $68 ;Program pointer (high) LDA #0 STA $2800 JSR $0648 ;Applesoft NEW command (Applesofi insists that the byte preceding the start of the program, $2800, be set to $00.) Second, a slot and drive number for our new device must be selected. This is most easily done by examining the DEVLST table to see what combinations are already in use and picking one that isn't. I,et's assume that slot 3, drive 1 is available. We then must store $30 in the DEVLST table (this is the code for a slot 3, drive 1 device; see Figure 7-1) and increment DEVCNT. Here's the code to do it: 10A #$30 INC DEVCNT 1DY DEVCNT STA OEV1ST,Y ;DEV1ST code for slot 3, drive 1 ;Adding one device ;DEVCNT now points to next available position in DEVLST ;Stuff device code in OEY1ST Writing a Pro DOS 8 Disk Driver 305 The next step is to install the address of the disk driver in the disk driver vector (low-order byte first). The address of the slot 3, drive 1 entry in this table is Here s how to store the address: LOA #<RAMOISK STA $0F16 IDA #>RAMOISK STA $8F17 ;Get low-order address byte ;Get high-order address byte BAMDISK is the address of the disk driver that performs the 1/0 operations. (We what it looks like in a moment.) Finally, we must initialize the volume directory block and the volume bit map. before we can do this, we must know three things: z The number of directory blocks z The block number of the volume bit map block z The number of blocks on the volume Since it's unlikely we'll be saving very many files in the 8K 111AM8 volume, we can some space by using just one directory block (instead of the four used on standard This block must be located at block 2 to conform to ProDOS conventions. The volume bit map block will be stored at block 3, leaving a total of 14 blocks- for file storage. To keep the file storage area contiguous, we assign these blocks numbers 4 through 17 and mark blocks 0 and 1 as in use in the volume bit map. (We can't use block 0 for file storage anyway since ProDOS uses a zero entry in a file index block as a placeholder for a sparse file.) This means ProDOS will think the volume size is 18 blocks (instead of 16), but that will not matter since the two extra blocks will not be available for file storage. Since a 1 bit in the volume bit map indicates a block is free, the volume bit map block must begin with a $0F byte (blocks ~ in use, blocks ~7 free), followed by an $FF byte (blocks 8-15 free) and a $C0 byte (blocks 16 and 17 free). The remaining bytes in the block will never be used but should be set to zero. With this background information, it is relatively simple to initialize 111AM8. The first step is to prepare an image of thc volume directory block and then use the WRITE - BLOCK command to write it to block 2. (You may want to review Chapter 2 for a description of the structure of such a block.) Every byte in the block will be zero except the following: $04 storage type code and name length ($F4) $O5-$08 ASCII string for "RAM8" ($52 $41 $40 $38) $22 access code ($C3) $23 entry length ($27) $24 entries per block ($00) 306 Disk Devices $27-$28 block number for volume bit map ($0003) $29-$2A number of blocks on volume ($0012) Since the directory links (at $00-$01 and $02-$03 in the block) are both zero, this will be the only block that ProDOS examines for files in the volume directory. The final step in the initialization procedure is to write an image of the volume bit map to block 3. Now all we have to do is write the special 111AM8 disk driver. Before we begin, we must decide what memory locations will be used to hold each block in the volume. A convenient mapping scheme to use is as follows: block 2 --> $8OO-$9FF block 3 --> $AOO-$BFF block 4 --> $COO-$OFF block 17 --> $26OO-$27FF (The driver returns an error code if a block number greater than 17 is requested.) With this scheme in place, the page number for a given block is equal to twice the block number plus 4. This number can be easily calculated by the driver subroutine. (To simplily the driver, we also assign block 0 to $40~$5FF and block 1 to $60~$7FF even though these blocks are never used.) As we saw earlier in this chapter, when the disk driver takes control, certain parame- ters are set up in zero page by the calling program. One of these parameters is a command code that indicates what type of operation is to be performed: read, write, check status, or format. To save space, our driver won't include the formatting code, so we ignore all format requests. Status requests will also be ignored because such requests are meaning- less in the context of a RAMdisk. Here's what the driver will look like: (required by ProDOS 8) Save zero page locations ;Check block number (high) ;Error if not zero Check block number (low) Is it out of bounds? It's >=18, so error Multiply block by 2 .... and add 4 to get ;starting page of block CLD LDA $6 STA ZPSAVE IDA $7 STA ZPSAVE+1 LDA $47 BNE IOERROR LDA $46 CMP #18 BCS IOERROR ASL CLC ADC #4 STA $7 Writing a ProDOS 8 Disk Driver 307 LDA #0 STA $6 LDA $42 ;Get command code CMP #3 ;Format? BEQ EXIT Yes, so exit normally CMP #0 ;Check status? BEQ EXIT Yes, so exit normally CMP #1 ;Read? BEQ READ Yes, so branch CMP #2 ;Write? BEQ WRITE Yes, so branch EXIT CLC ;CLC ==> no error LDA #0 EXIT1 PHP PHA LDA ZPTEMP ;Restore zero page locations STA $6 LDA ZPTEMP~1 STA $7 PLA Restore error code PLP ;Restore carry status RTS IOERROR SEC ;SEC ==> error occurred LDA #$27 1/0 ERROR code READ WRITE ZPTEMP BNE EXIT1 (always taken) ["read" -,'ubroutine] JMP EXIT ["write" subroutine] JMP EXIT DS 2 ;Temporary storage space Note that the driver must begin with the CLD instruction that ProDOS 8 checks to s~ a valid driver is installed. The first part of the driver saves the contents of two zero locations we're going to overwrite and then checks whether the requested block (stored at $4~$47) is within the allowable range. If it isn't, the driver ends with the flag set and the error code for "I/O error" ($27) in the accumulator. The next part simply calculates the address of the requested block and stores it two consecutive zero page locations ($~$7) so that the driver can access the block data using the 6502 indirect indexed addressing mode. The bodies of the READ and WRITE subroutines are both very simple to '+ The READ code is responsible for moving the block of data from the address - 308 Disk Devices calculated to the address specified by the caller. (This address is stored at $4~$45.) The WRITE code performs just the opposite transfer. Here are the two subroutines that will do the trick: READ LDY #0 RI LDA ($6),Y Get block data STA ($44),Y ; and move it to caller's buffer INY BNE RI Branch until 256 bytes done INC $6 Move to second half INC $44 R2 LDA ($6),Y Get block data STA ($44),Y ; and move it to caller's buffer INY BNE R2 WRITE WI W2 Branch until 256 bytes done DEC $44 JMP EXIT LDY #0 LDA ($44),Y ;Get data from caller's buffer STA ($6),Y ; and move it to "disk" block INY BNE RI Branch until 256 bytes done INC $44 ;Move to second half INC $6 LDA ($44),Y ;Get data from caller's buffer STA ($6),Y ; and move it to "disk" block INY BNE R2 Branch until 256 bytes done DEC $44 JMP EXIT As you can see, an 1/0 operation is simply the movement of a 512-byte block of data from one area of memory to another. Table 7-3 shows the complete source listing for a slightly embellished form of this driver. One additional feature it includes is the marking of pages 3 and ~7 as "in use" in the system bit map in the ProDOS 8 global page to prevent the 111AM8 volume from being overwritten. Any attempt to load a file into these areas (using BLOAD or BRUN) results in a "no buffers available" error. Use the BRUN command to install the driver program, and then prove to yourself that it exists by entering the command: CATALOG /RAM8 (or CATAL0G,S3,DI) You should see a standard CATALOG listing followed by an indication that there are 14 blocks free and 4 blocks used, as expected. You can now save files to 111AM8 as you would to any other volume. Writing a ProDOS 8 Disk Driver 309 Table 7-3 The 111AM8 disk driver program 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 2000: A0 00 34 2002: 89 F4 20 35 2005: 99 00 03 36 2008: C8 37 2009: CO 7C 38 2008: 00 F5 39 40 41 42 43 44 45 46 2000: AD 58 BF 47 2010: 09 10 48 2012: 80 58 BF 49 2015: A9 FF 50 310 Disk Devices