@database "cd"

@Node Main "cd.doc"
@toc "Includes_&_Autodocs/Main"
    @{" CD_ADDCHANGEINT " Link "CD_ADDCHANGEINT"}
    @{" CD_ADDFRAMEINT " Link "CD_ADDFRAMEINT"}
    @{" CD_ATTENUATE " Link "CD_ATTENUATE"}
    @{" CD_CHANGENUM " Link "CD_CHANGENUM"}
    @{" CD_CHANGESTATE " Link "CD_CHANGESTATE"}
    @{" CD_CONFIG " Link "CD_CONFIG"}
    @{" CD_EJECT " Link "CD_EJECT"}
    @{" CD_GETGEOMETRY " Link "CD_GETGEOMETRY"}
    @{" CD_INFO " Link "CD_INFO"}
    @{" CD_MOTOR " Link "CD_MOTOR"}
    @{" CD_PAUSE " Link "CD_PAUSE"}
    @{" CD_PLAYLSN " Link "CD_PLAYLSN"}
    @{" CD_PLAYMSF " Link "CD_PLAYMSF"}
    @{" CD_PLAYTRACK " Link "CD_PLAYTRACK"}
    @{" CD_PROTSTATUS " Link "CD_PROTSTATUS"}
    @{" CD_QCODELSN " Link "CD_QCODELSN"}
    @{" CD_QCODEMSF " Link "CD_QCODEMSF"}
    @{" CD_READ " Link "CD_READ"}
    @{" CD_READXL " Link "CD_READXL"}
    @{" CD_REMCHANGEINT " Link "CD_REMCHANGEINT"}
    @{" CD_REMFRAMEINT " Link "CD_REMFRAMEINT"}
    @{" CD_SEARCH " Link "CD_SEARCH"}
    @{" CD_SEEK " Link "CD_SEEK"}
    @{" CD_TOCLSN " Link "CD_TOCLSN"}
    @{" CD_TOCMSF " Link "CD_TOCMSF"}
    @{" CloseDevice() " Link "CloseDevice()"}
    @{" OpenDevice() " Link "OpenDevice()"}
@EndNode

@Node "CD_ADDCHANGEINT" "cd.device/CD_ADDCHANGEINT"

@{b}   NAME@{ub}
       CD_ADDCHANGEINT -- add a disk change software interrupt handler.

@{b}   FUNCTION@{ub}
       This command lets you add a software interrupt handler to the
       disk device that gets invoked whenever a disk insertion or removal
       occurs.

       You must pass in a properly initialized Exec @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure
       and be prepared to deal with disk insertions/removals immediately.
       The interrupt is generated by the exec Cause function, so you must
       preserve A6.

       To set up the handler, an @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure must be initialized.
       This structure is supplied as the io_Data to the CD_ADDCHANGEINT
       command.  The handler then gets linked into the handler chain and
       gets invoked whenever a disk change happens.  You must eventually
       remove the handler before you exit.

       This command only returns when the handler is removed. That is,
       the device holds onto the IO request until the @{"CD_REMCHANGEINT" Link "CD_REMCHANGEINT"} command
       is executed with that same IO request.  Hence, you must use @{"SendIO()" Link "exec/SendIO()"}
       with this command.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_ADDCHANGEINT
       io_Length       sizeof(struct Interrupt)
       io_Data         pointer to @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   SEE ALSO@{ub}
       @{"CD_REMCHANGEINT" Link "CD_REMCHANGEINT"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}, @{"<exec/interrupts.h>" Link "includes/exec/interrupts.h/Main" 0},
       @{"exec.library/Cause()" Link "exec/Cause()"}

@EndNode

@Node "CD_ADDFRAMEINT" "cd.device/CD_ADDFRAMEINT"

@{b}   NAME@{ub}
       CD_ADDFRAMEINT -- add a CD-frame software interrupt handler.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_ADDFRAMEINT
       io_Length       sizeof(struct Interrupt)
       io_Data         pointer to @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command lets you add a software interrupt handler to the
       disk device that gets invoked whenever a new frame is encountered
       while CD audio is being played.

       You must pass in a properly initialized Exec @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure
       and be prepared to deal with frame interrupts immediately.
       The interrupt is generated by the exec Cause function, so you must
       preserve A6.

       To set up the handler, an @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure must be initialized.
       This structure is supplied in io_Data of the CD_ADDFRAMEINT
       command.  The handler then gets linked into the handler chain and
       gets invoked whenever a frame event occurs.  You must eventually
       remove the handler before you exit.

       This command only returns when the handler is removed. That is,
       the device holds onto the IO request until the @{"CD_REMFRAMEINT" Link "CD_REMFRAMEINT"} command
       is executed with that same IO request.  Hence, you must use @{"SendIO()" Link "exec/SendIO()"}
       with this command.

@{b}   NOTES@{ub}
       The interrupt handler can be added before or after a play command is
       sent.  Interrupts will only be generated while CD audio is playing.
       Interrupts will not be generated when audio is paused.

@{b}   SEE ALSO@{ub}
       @{"CD_REMFRAMEINT" Link "CD_REMFRAMEINT"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}, @{"<exec/interrupts.h>" Link "includes/exec/interrupts.h/Main" 0},
       @{"exec.library/Cause()" Link "exec/Cause()"}

@EndNode

@Node "CD_ATTENUATE" "cd.device/CD_ATTENUATE"

@{b}   NAME@{ub}
       CD_ATTENUATE -- Attenuate CD audio volume (immediately or gradually)

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_ATTENUATE
       io_Data         NULL
       io_Length       duration of volume fade in frames
       io_Offset       target volume level (0 - 0x7FFF) (-1 = status only)

@{b}   RESULTS@{ub}
       io_Error        Returns an error if drive does not support attenuation
       io_Actual       current volume level (fade may be monitored)

@{b}   FUNCTION@{ub}
       This command will ramp the CD audio volume up or down from its
       current value to the value contained in io_Offset.  The range is 0
       (silence) to 0x7FFF (full volume).  If -1 is specified as the target,
       the attenuation will not be modified; the current attenuation value
       will be returned in io_Actual.

       io_Length contains the duration of the fade.  In seconds, this is
       io_Length divided by the current frame rate (usually 75).

       Note that this command returns before the fade has completed.  Thus,
       once started, a fade cannot be aborted.  You can, however, send a
       new CD_ATTENUATE command, which will immediately override any fade
       currently in progress.  An io_Length of zero means attenuate
       immediately.

       If a gradual attenuation command is sent before the play command, the
       fade will begin as soon as the play command is sent.

@{b}   EXAMPLE@{ub}

@{b}   NOTES@{ub}
       This command has no effect on Amiga audio volume, only CD audio.

       If the drive does not support volume attenuation, but does support
       mute, a value of under $0800 should be considered mute, and equal
       to or above should be full volume.  If chunky attenuation is
       supported, the drive should do the best it can.  If the drive does
       not support volume attenuation at all, an error should be returned.
       Even if only mute is supported, if gradual attenuation is requested,
       the device should still emulate the fade command and mute based on
       the $0800 boundary.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_INFO" Link "CD_INFO"}

@EndNode

@Node "CD_CHANGENUM" "cd.device/CD_CHANGENUM"

@{b}   NAME@{ub}
       CD_CHANGENUM -- return the current value of the disk-change counter.

@{b}   FUNCTION@{ub}
       This command returns the current value of the disk-change counter
       The disk change counter is incremented each time a disk is inserted
       or removed from the cd unit.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_CHANGENUM

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - if io_Error is 0, this contains the current value of the
                   disk-change counter.

@EndNode

@Node "CD_CHANGESTATE" "cd.device/CD_CHANGESTATE"

@{b}   NAME@{ub}
       CD_CHANGESTATE -- check if a "valid" disk is currently in a drive.

@{b}   FUNCTION@{ub}
       This command checks to see if there is a "valid" disk in a drive.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_CHANGESTATE

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - 0 means there is a disk while anything else indicates
                   there is no disk.

@{b}   NOTES@{ub}
       A "valid" disk is a disk with a readable table of contents.

@EndNode

@Node "CD_CONFIG" "cd.device/CD_CONFIG"

@{b}   NAME@{ub}
       CD_CONFIG -- Set drive preferences

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_CONFIG
       io_Data         pointer to first entry of TagList
       io_Length       0

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command sets one or more of the configuration items.
       The configuration items are:

       TAGCD_PLAYSPEED                 Default: 75
       TAGCD_READSPEED                 Default: 75 (do not count on this)
       TAGCD_READXLSPEED               Default: 75
       TAGCD_SECTORSIZE                Default: 2048
       TAGCD_XLECC                     Default: 1 (on)
       TAGCD_EJECTRESET                Default: can be 0 (off) or 1 (on)

       The speed settings are described in the number of frames (sectors)
       per second.  All CD-ROM drives are capable of the 75 frames/second
       rate.  Some drives are capable of 150 frames/second, and some even
       more.  To determine the maximum frame rate of the drive, use the
       @{"CD_INFO" Link "CD_INFO"} command.  Valid values for caddyless Commodore CD-ROM drives
       are 75 and 150 (normal speed and double speed).  All other values are
       invalid.  You should always make sure the drive is capable of the
       configuration you are requesting by either using the @{"CD_INFO" Link "CD_INFO"} command,
       and/or by checking for an error condition after submitting your
       request.

       There are three different types of CD-ROM sectors.  Mode 1 sectors
       (2048 bytes), mode 2 form 1 sectors (2048 bytes), and mode 2 form 2
       sectors (2328 bytes).  Normally, disks are encoded in Mode 1 format.
       Mode 2 form 1 is basically the same as mode 1; however, the mode 2
       form 2 sector format contains no CD-ROM error correction information.
       In order to read information encoded in this sector format, the
       drive's sector size must be configured to 2328 byte sectors.

       Error correction (ECC) of the READXL command can be turned off or
       on with this command.  Error correction can be implemented in either
       hardware or software (depending on the CD-ROM drive).  When ECC is
       implemented in software, CPU usage can become bursty.  Errors rarely
       occur on CDs unless they have numerous scratches, but when they do
       occur, they will cause a loss of CPU bandwith.  When ECC is
       implemented in hardware, no CPU bandwidth is lost -- in this case,
       ECC will always be on no matter how you configure the drive because 
       it is free.  The READXL command is used primarily for displaying
       movie-like data.  In this case, speed is essential and data integrety
       is not; however, if the CPU is not being utilized during an XL
       animation there is no need to disable ECC (since the bandwidth is
       there to be used).  The only time ECC should be disabled is when you
       are doing intense calculations in the background of a READXL command,
       AND your program is time-critical.  Do not forget to change this back
       when you are done!
       
       To make the computer reset when a CD is ejected (for an application
       that does not exit), use the TAGCD_EJECTRESET tag.  When possible,
       titles should be able to exit cleanly back to Workbench.  Error
       conditions should be monitored when doing disk I/O.

@{b}   EXAMPLE@{ub}
       /* Configure ReadXL for double-speed reading and turn off ECC when */
       /* the ReadXL command is used.                                     */
       
       struct @{"TagItem" Link "includes/utility/tagitem.h/Main" 31} ConfigList[] = {

           { TAGCD_READXLSPEED, 150 },
           { TAGCD_XLECC,       0   },
           { TAG_END,           0   }
           };

           ior->io_Command = CD_CONFIG;
           ior->io_Data    = (APTR)&ConfigList;
           ior->io_Length  = 0;
           DoIO(ior);

           if (ior->io_Error) printf("Could not be configured\n");

@{b}   NOTES@{ub}
       Setting the configuration will not modify the behavior of a read or
       play command already in progress.

       This can be a very dangerous command.  If for instance you set
       TAGCD_SECTORSIZE to 2328, you will no longer be able to read any
       data encoded at 2048 byte sectors (e.g. the file system will not be
       able to read the disk anymore).  After you read any data stored with
       this sector format, you should immediately configure back to the
       original default value (even if the read failed -- the disk could
       be removed in the middle of your read).  You should NEVER use this
       command if you are not the exclusive owner of your disk.

@{b}   BUGS@{ub}
       TAG_IGNORE, TAG_MORE, and TAG_SKIP do not work.  Do not use these.

       When switching speeds from single to double (or double to single),
       If the drive is prefetching in single-speed the data you are going
       to use in double-speed, the drive will not switch to double-speed
       (and visa versa).  To avoid this problem, switch to the desired speed,
       begin reading at least 4k into the data (just read two bytes), then
       begin reading at the beginning.  This will force the prefetch buffer
       to clear and issue a new read command with the desired speed.
       (Fixed in 40.24).

@{b}   SEE ALSO@{ub}
       @{"CD_INFO" Link "CD_INFO"}, @{"<utility/tagitem.h>" Link "includes/utility/tagitem.h/Main" 0}

@EndNode

@Node "CD_EJECT" "cd.device/CD_EJECT"

@{b}   NAME@{ub}
       CD_EJECT -- Open or close the CD's drive door

@{b}   IO REQUEST@{ub}
       io_Command      CD_EJECT
       io_Data         NULL
       io_Length       requested state of drive door (0 == close, 1 == open)
       io_Offset       0

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual       previous state of drive door

@{b}   FUNCTION@{ub}
       This command causes the CD-ROM drive's door to open or close.
       The desired state of the drive door is placed in io_Length.  The
       previous state of the drive door is returned in io_Actual.

@{b}   EXAMPLE@{ub}

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}

@EndNode

@Node "CD_GETGEOMETRY" "cd.device/CD_GETGEOMETRY"

@{b}   NAME@{ub}
       CD_GETGEOMETRY -- return the geometry of the drive.

@{b}   FUNCTION@{ub}
       This command returns a full set of information about the
       layout of the drive. The information is returned in the
       @{"DriveGeometry" Link "includes/devices/trackdisk.h/Main" 134} structure pointed to by io_Data.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_GETGEOMETRY
       io_Data         pointer to a @{"DriveGeometry" Link "includes/devices/trackdisk.h/Main" 134} structure
       io_Length       sizeof(struct DriveGeometry)

@{b}   IO REQUEST RESULT@{ub}
       io_Error  - 0 for success, or an error code as defined in
                   @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - length of data transferred.

@{b}   SEE ALSO@{ub}
       CD_GETNUMTRACKS, @{"<devices/trackdisk.h>" Link "includes/devices/trackdisk.h/Main" 0}

@EndNode

@Node "CD_INFO" "cd.device/CD_INFO"

@{b}   NAME@{ub}
       CD_INFO -- Return information/status of device

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_INFO
       io_Data         pointer to @{"CDInfo" Link "includes/devices/cd.h/Main" 132} structure
       io_Length       sizeof(struct CDInfo)

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual       length of data transferred

@{b}   FUNCTION@{ub}

       This command returns current configurations and status of the device
       driver.

@{b}   EXAMPLE@{ub}

       struct @{"CDInfo" Link "includes/devices/cd.h/Main" 132} Info;

       ior->io_Command = CD_INFO;               /* Retrieve drive info.    */
       ior->io_Data    = (APTR)Info;            /* Here's where we want it */
       ior->io_Length  = sizeof(struct CDInfo); /* Return whole structure  */
       DoIO(ior);

       if (!ior->io_Error) {                    /* Command succeeded       */

           if (Info.Status & CDSTSF_PLAYING) printf("Audio is playing\n");
           else                              printf("Audio not playing\n");
           }

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_MOTOR" "cd.device/CD_MOTOR"

@{b}   NAME@{ub}
       CD_MOTOR -- control the on/off state of a drive motor.

@{b}   FUNCTION@{ub}
       This command gives control over the spindle motor.  The motor may be
       turned on or off.

       If the motor is just being turned on, the device will delay the
       proper amount of time to allow the drive to come up to speed.
       Turning the motor on or off manually is not necessary, the device does
       this automatically if it receives a request when the motor is off.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_MOTOR
       io_Length       the requested state of the motor, 0 to turn the motor
                       off, and 1 to turn the motor on.

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - if io_Error is 0 this contains the previous state of the
                   drive motor.

@EndNode

@Node "CD_PAUSE" "cd.device/CD_PAUSE"

@{b}   NAME@{ub}
       CD_PAUSE -- Pause or unPause play command.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_PAUSE
       io_Data         NULL
       io_Length       pausemode : 1 = pause play; 0 = do not pause play;
       io_Offset       0

@{b}   RESULTS@{ub}
       io_Actual - if io_Error is 0, this contains the previous pause state.

@{b}   FUNCTION@{ub}
       This command will place the CD in, or take the CD out of pause mode.
       The desired pause state is placed in io_Length.  This command only
       effects play commands.  When the audio is playing and the pausemode
       is set, this command will immediately pause the audio output
       suspending the play command until the play is unpaused.  When audio
       is not playing and the pausemode is set, this command will set the
       pause mode (having no immediate effect).  When a play command is
       submitted, the laser will seek to the appropriate position and pause
       at that spot.  The play command will be suspended until the play is
       unpaused (or the play is aborted).

@{b}   EXAMPLE@{ub}

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}

@EndNode

@Node "CD_PLAYLSN" "cd.device/CD_PLAYLSN"

@{b}   NAME@{ub}
        CD_PLAYLSN -- Play a selected portion of CD audio (LSN form).

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_PLAYLSN
       io_Data         NULL
       io_Length       length of play
       io_Offset       starting position

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command causes the drive to start playing CD audio from the
       specified position until the specified length has passed.

       io_Offset specifies the starting position.  io_Length contains
       the amount of time to play.  All data is specified in LSN format.

       A @{"DoIO()" Link "exec/DoIO()"} will not return until the requested number of sectors
       have been played.  A @{"SendIO()" Link "exec/SendIO()"} will return as soon as the PLAY
       has been started.  At this time other commands can be sent (like
       CD_PAUSE).  To stop a play before the specified length has been
       reached, use @{"AbortIO()" Link "timer/AbortIO()"}.

@{b}   EXAMPLE@{ub}
       /* Play two minutes, ten seconds of audio starting at 20 minutes, */
       /* 58 seconds, and 10 frames.                                     */

       ior->io_Command = CD_PLAYLSN;   /* Play CD audio           */
       ior->io_Offset  = 94360;        /* 20*(60*75) + 58*75 + 10 */
       ior->io_Length  = 9750;         /* 02*(60*75) + 10*75 + 00 */
       @{"DoIO" Link "exec/DoIO()"} (ior);

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_PLAYTRACK" Link "CD_PLAYTRACK"}, @{"CD_PAUSE" Link "CD_PAUSE"}, @{"CD_SEARCH" Link "CD_SEARCH"}, @{"CD_ATTENUATE" Link "CD_ATTENUATE"}

@EndNode

@Node "CD_PLAYMSF" "cd.device/CD_PLAYMSF"

@{b}   NAME@{ub}
        CD_PLAYMSF -- Play a selected portion of CD audio (MSF form).

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_PLAYMSF
       io_Data         NULL
       io_Length       length of play
       io_Offset       starting position

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command causes the drive to start playing CD audio from the
       specified position until the specified length has passed.

       io_Offset specifies the starting position.  io_Length contains
       the amount of time to play.  All data is specified in MSF format.

       A @{"DoIO()" Link "exec/DoIO()"} will not return until the requested number of sectors
       have been played.  A @{"SendIO()" Link "exec/SendIO()"} will return as soon as the PLAY
       has been started.  At this time other commands can be sent (like
       CD_PAUSE).  To stop a play before the specified length has been
       reached, use @{"AbortIO()" Link "timer/AbortIO()"}.

@{b}   EXAMPLE@{ub}
       /* Play two minutes, ten seconds of audio starting at 20 minutes, */
       /* 58 seconds, and 10 frames.                                     */

       ior->io_Command = CD_PLAYMSF;   /* Play CD audio          */
       ior->io_Offset  = 0x00143A0A;   /* $14=20, $3A=58, $0A=10 */
       ior->io_Length  = 0x00020A00;   /* $02=02, $0A=10, $00=00 */
       @{"DoIO" Link "exec/DoIO()"} (ior);

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_PLAYTRACK" Link "CD_PLAYTRACK"}, @{"CD_PAUSE" Link "CD_PAUSE"}, @{"CD_SEARCH" Link "CD_SEARCH"}, @{"CD_ATTENUATE" Link "CD_ATTENUATE"}

@EndNode

@Node "CD_PLAYTRACK" "cd.device/CD_PLAYTRACK"

@{b}   NAME@{ub}
       CD_PLAYTRACK -- Play one or more tracks of CD audio.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_PLAYTRACK
       io_Data         NULL
       io_Length       number of tracks to play
       io_Offset       start playing at beginning of this track

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
@{b}   FUNCTION@{ub}
       This command causes the drive to play the specified audio track(s).
       The command will return when the audio has completed.

       io_Offset specifies the track number (starting from 1).

       io_Length specifies the number of tracks to play (0 is invalid).  

@{b}   EXAMPLE@{ub}

       ior->io_Command = CD_PLAYTRACK;    /* Play audio tracks     */
       ior->io_Offset  = STARTTRACK;      /* Start with this track */
       ior->io_Length  = 3;               /* Play three tracks     */
       DoIO(ior);

@{b}   NOTES@{ub}

       PLAY commands are asynchronous with many other CD commands.
       Using a separate I/O request, other commands can be sent to the device
       that can change the behavior of the PLAY command.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_PLAYMSF" Link "CD_PLAYMSF"}, @{"CD_PLAYLSN" Link "CD_PLAYLSN"}, @{"CD_PAUSE" Link "CD_PAUSE"}, @{"CD_SEARCH" Link "CD_SEARCH"}, @{"CD_ATTENUATE" Link "CD_ATTENUATE"}

@EndNode

@Node "CD_PROTSTATUS" "cd.device/CD_PROTSTATUS"

@{b}   NAME@{ub}
       CD_PROTSTATUS -- return whether the current disk is write-protected.

@{b}   FUNCTION@{ub}
       This command is used to determine whether the current disk is
       write-protected.  Currently, this function always returns write-
       protected status.  If write-once CDs are made available at some point,
       this may change.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_PROTSTATUS

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - 0 means the disk is NOT write-protected, while any other
                   value indicates it is.

@EndNode

@Node "CD_QCODELSN" "cd.device/CD_QCODELSN"

@{b}   NAME@{ub}
       CD_QCODELSN -- Report current disk position.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_QCODELSN
       io_Data         pointer to @{"QCode" Link "includes/devices/cd.h/Main" 284} structure
       io_Length       0 - MUST be zero (for future compatability)

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command reports current subcode Q channel time information.  This
       command only returns data when CD Audio is playing (or paused).  At
       any other time, an error is returned.  The Q-Code packet consists of:

       struct @{"QCode" Link "includes/devices/cd.h/Main" 284} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        CtlAdr;        /* Data type / @{"QCode" Link "includes/devices/cd.h/Main" 284} type           */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Track;         /* Track number                     */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Index;         /* Track subindex number            */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Zero;          /* The "Zero" byte of Q-Code packet */
           union LSNMSF TrackPosition; /* Position from start of track     */
           union LSNMSF DiskPosition;  /* Position from start of disk      */
           };

@{b}   EXAMPLE@{ub}

       struct @{"QCode" Link "includes/devices/cd.h/Main" 284} qcode;

       ior->io_Command = CD_QCODELSN;  /* Retrieve TOC information */
       ior->io_Length  = 0;            /* MUST be zero             */
       ior->io_Data    = (APTR)qcode;  /* Here's where we want it  */
       @{"DoIO" Link "exec/DoIO()"} (ior);

       if (!ior->io_Error) {           /* Command succeeded        */

           printf("Current position is: %ld\n", qcode.DiskPosition.LSN);
           }

@{b}   NOTES@{ub}
       This function may not return immediately.  It may take several frames
       to pass by before a valid Q-Code packet can be returned.  Use @{"SendIO()" Link "exec/SendIO()"}
       and @{"CheckIO()" Link "exec/CheckIO()"} if response time is critical, and the information is
       not.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_PLAYMSF" Link "CD_PLAYMSF"}, @{"CD_PLAYLSN" Link "CD_PLAYLSN"}, @{"CD_PLAYTRACK" Link "CD_PLAYTRACK"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_QCODEMSF" "cd.device/CD_QCODEMSF"

@{b}   NAME@{ub}
       CD_QCODEMSF -- Report current disk position.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_QCODEMSF
       io_Data         pointer to @{"QCode" Link "includes/devices/cd.h/Main" 284} structure
       io_Length       0 - MUST be zero (for future compatability)

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command reports current subcode Q channel time information.  This
       command only returns data when CD Audio is playing (or paused).  At 
       any other time, an error is returned.  The Q-Code packet consists of:

       struct @{"QCode" Link "includes/devices/cd.h/Main" 284} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        CtlAdr;        /* Data type / @{"QCode" Link "includes/devices/cd.h/Main" 284} type           */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Track;         /* Track number                     */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Index;         /* Track subindex number            */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Zero;          /* The "Zero" byte of Q-Code packet */
           union LSNMSF TrackPosition; /* Position from start of track     */
           union LSNMSF DiskPosition;  /* Position from start of disk      */
           };

@{b}   EXAMPLE@{ub}

       struct @{"QCode" Link "includes/devices/cd.h/Main" 284} qcode;

       ior->io_Command = CD_QCODEMSF;  /* Retrieve TOC information */
       ior->io_Length  = 0;            /* MUST be zero             */
       ior->io_Data    = (APTR)qcode;  /* Here's where we want it  */
       @{"DoIO" Link "exec/DoIO()"} (ior);

       if (!ior->io_Error) {           /* Command succeeded        */

           printf("Current position is: %02d:%02d:%02d\n",
               qcode.DiskPosition.MSF.Minute,
               qcode.DiskPosition.MSF.Second,
               qcode.DiskPosition.MSF.Frame);
           }

@{b}   NOTES@{ub}
       This function may not return immediately.  It may take several frames
       to pass by before a valid Q-Code packet can be returned.  Use @{"SendIO()" Link "exec/SendIO()"}
       and @{"CheckIO()" Link "exec/CheckIO()"} if response time is critical, and the information is
       not.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_PLAYMSF" Link "CD_PLAYMSF"}, @{"CD_PLAYLSN" Link "CD_PLAYLSN"}, @{"CD_PLAYTRACK" Link "CD_PLAYTRACK"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_READ" "cd.device/CD_READ"

@{b}   NAME@{ub}
       CD_READ -- read data from disk.

@{b}   FUNCTION@{ub}
       Reads data from the CD into memory.  Data may be accessed on WORD
       boundaries (you are not restricted to sector boundaries as with
       normal disk devices).  Data lengths can also be described in WORD
       amounts.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_READ
       io_Data         pointer to the buffer where the data should be put
       io_Length       number of bytes to read, must be a WORD multiple.
       io_Offset       byte offset from the start of the disk describing
                       where to read data from, must be a WORD multiple.

@{b}   IO REQUEST RESULT@{ub}
       io_Error  - 0 for success, or an error code as defined in
                   @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual - if io_Error is 0, number of bytes actually transferred

@{b}   NOTES@{ub}
       If an error occurs when attempting a CD_READ, the software will
       retry up to 10 times before giving up on the request.  If the
       drive is in double-speed and an error occurs, the software will
       retry once more in double-speed, and if this fails, will retry
       the next 9 times in single-speed.

@{b}   SEE ALSO@{ub}
       @{"CD_READXL" Link "CD_READXL"}

@EndNode

@Node "CD_READXL" "cd.device/CD_READXL"

@{b}   NAME@{ub}
       CD_READXL -- Read from CD-ROM into memory via transfer list.

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_READXL
       io_Data         pointer to transfer list (i.e. struct @{"List" Link "includes/exec/lists.h/Main" 19} *).
       io_Length       maximum transfer length (WORD multiple) or 0.
       io_Offset       byte offset from the start of the disk describing
                       where to read data from, must be a WORD multiple.

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as described in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual       if io_Error is 0, number of bytes actually transferred

@{b}   FUNCTION@{ub}
       This command starts reading data off the disk at the specified
       location and deposits it into memory according to the nodes in a
       transfer list.  The pointer to the list of transfer nodes is placed
       in io_Data.  If you have a non-circular transfer list, simply set
       io_Length to 0 (0 is special and means ignore io_Length) -- your
       transfer will end when your transfer list has been exhausted.  If you
       have a circular transfer list, the list will never end.  In this case,
       the transfer will terminate when io_Length bytes have been
       transferred.

       The fields in the @{"CDXL" Link "includes/devices/cd.h/Main" 225} node structure are:

       struct  @{"CDXL" Link "includes/devices/cd.h/Main" 225} {

           struct @{"MinNode" Link "includes/exec/nodes.h/Main" 30}  Node;         /* double linkage                */
           char           *Buffer;       /* data destination              */
           @{"LONG" Link "includes/exec/types.h/Main" 35}            Length;       /* must be even # bytes          */
           @{"LONG" Link "includes/exec/types.h/Main" 35}            Actual;       /* bytes transferred             */
           @{"APTR" Link "includes/exec/types.h/Main" 33}            IntData;      /* interrupt server data segment */
           VOID            (*IntCode)(); /* interrupt server code entry   */
           };

       The philosophy here is that you set up the buffers you want filled,
       create @{"CDXL" Link "includes/devices/cd.h/Main" 225} nodes describing the locations and sizes of these
       buffers, link all the nodes together in the order that you'd like
       (even make a circular list for animations), and execute the command.
       The data will be streamed into the appropriate buffers until the
       list has been exhausted, an entry with a Length of zero is
       encountered, io_Length bytes have been transferred (if io_Length is
       non-zero), or the command is aborted with @{"AbortIO()" Link "timer/AbortIO()"}.

       If you fill in the (*IntCode)() field with a pointer to an interrupt
       routine, your routine will be called when the transfer for the node
       is complete.  Your code will be called before the driver proceeds to
       the next node.  The interrupt should follow the same rules as standard
       interrupts (see @{"AddIntServer" Link "exec/AddIntServer()"} of Exec autodocs).  Register A2 will
       contain a pointer to the node just completed.  You may manipulate the
       list from within the interrupt. Your code must be brief (this is an
       interrupt).  When returning from this interrupt, D0 should be cleared
       and an RTS instruction should be used to return.

       Servers are called with the following register conventions:

           D0 - scratch
           D1 - scratch

           A0 - scratch
           A1 - server is_Data pointer (scratch)
           A2 - pointer to @{"CDXL" Link "includes/devices/cd.h/Main" 225} node just completed

           A5 - jump vector register (scratch)

           all other registers must be preserved

@{b}   EXAMPLE@{ub}

@{b}   NOTES@{ub}
       Try to make sure that small buffers are not overused.  Each time
       a node is completed, an interrupt is generated.  If you find that
       your computer is acting sluggish, or the CD_READXL command is
       aborting, you are probably generating too many interrupts.  It is
       not efficient to have more than a few of these interrupts generated
       within a vertical blank.

       Unlike the READ command, the READXL command will not retry a sector
       if there is an error.  Since the READXL command's purpose is primarily
       for animations, data streaming is considered more important than the
       data itself.  An error will be returned in io_Error if a data error
       did occur.  This command will never drop to a lower speed in the event
       of an error.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CMD_READ" Link "trackdisk/CMD_READ"}, @{"CD_SEEK" Link "CD_SEEK"}, Autodocs - @{"AddIntServer" Link "exec/AddIntServer()"}

@EndNode

@Node "CD_REMCHANGEINT" "cd.device/CD_REMCHANGEINT"

@{b}   NAME@{ub}
       CD_REMCHANGEINT -- remove a disk change software interrupt handler.

@{b}   FUNCTION@{ub}
       This command removes a disk change software interrupt added
       by a previous use of @{"CD_ADDCHANGEINT" Link "CD_ADDCHANGEINT"}.

@{b}   IO REQUEST INPUT@{ub}
       The same IO request used for @{"CD_ADDCHANGEINT" Link "CD_ADDCHANGEINT"}.

       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_REMCHANGEINT
       io_Length       sizeof(struct Interrupt)
       io_Data         pointer to @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   SEE ALSO@{ub}
       @{"CD_ADDCHANGEINT" Link "CD_ADDCHANGEINT"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_REMFRAMEINT" "cd.device/CD_REMFRAMEINT"

@{b}   NAME@{ub}
       CD_REMFRAMEINT -- remove a CD-frame interrupt handler.

@{b}   IO REQUEST@{ub}
       The same IO request used for @{"CD_ADDFRAMEINT" Link "CD_ADDFRAMEINT"}.

       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_REMFRAMEINT
       io_Length       sizeof(struct Interrupt)
       io_Data         pointer to @{"Interrupt" Link "includes/exec/interrupts.h/Main" 21} structure

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@{b}   FUNCTION@{ub}
       This command removes a CD-frame software interrupt added
       by a previous use of @{"CD_ADDFRAMEINT" Link "CD_ADDFRAMEINT"}.

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}
       @{"CD_ADDFRAMEINT" Link "CD_ADDFRAMEINT"}, @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_SEARCH" "cd.device/CD_SEARCH"

@{b}   NAME@{ub}
       CD_SEARCH -- configure the mode in which PLAY commands play

@{b}   IO REQUEST@{ub}
       io_Command      CD_SEARCH
       io_Data         NULL
       io_Length       searchmode
       io_Offset       0

@{b}   RESULTS@{ub}
       io_Actual - if io_Error is 0, this contains the previous search mode.

@{b}   FUNCTION@{ub}
       This command causes a play command to play in fast-forward,
       fast-reverse, or normal play mode.  These modes are defined as:

       CDMODE_NORMAL   0   Normal play (current speed setting)
       CDMODE_FFWD     1   Play in fast forward mode  
       CDMODE_FREV     2   Play in fast reverse mode

       The search mode can be set before the play command is sent, or during
       a play.  If CD_SEARCH is sent before a play command is sent, the
       mode is set and the command immediately returns.  If the mode is set
       to REV mode, when the play command is sent the play will begin at the
       requested end position and work backwards to the start position.

       If CD_SEARCH is sent during a play, the play will automatically
       switch to the desired mode and continue playing until the original
       play command is completed.  If REV mode is set and the beginning of
       the play is encountered before switching back to forward play, the
       play command will terminate with no error.

@{b}   EXAMPLE@{ub}
       /* Search in fast forward mode. */
       ior->io_Command = CD_SEARCH;
       ior->io_Data    = NULL;
       ior->io_Offset  = 0;
       ior->io_Length  = CDMODE_FFWD;
       DoIO(ior);

@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}

@EndNode

@Node "CD_SEEK" "cd.device/CD_SEEK"

@{b}   NAME@{ub}
       CD_SEEK -- position laser at specified location.

@{b}   FUNCTION@{ub}
       CD_SEEK moves the laser to the approximate position specified.  The
       io_Offset field should be set to the offset to which the head is
       to be positioned.

@{b}   IO REQUEST INPUT@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_SEEK
       io_Offset       position where head is to be moved (always LSN format)

@{b}   IO REQUEST RESULT@{ub}
       io_Error - 0 for success, or an error code as defined in
                  @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}

@EndNode

@Node "CD_TOCLSN" "cd.device/CD_TOCLSN"

@{b}   NAME@{ub}
       CD_TOCLSN -- Return table of contents information from CD (LSN form).

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_TOCLSN
       io_Data         pointer to array where TOC is to be stored
       io_Length       number of CDTOC entries to be fetched
       io_Offset       entry to begin at (entry 0 is summary information)

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual       Actual number of entries copied

@{b}   FUNCTION@{ub}
       This command returns the table of contents of the disk currently in
       the drive.  The table of contents consists of up to 100 entries.
       Entry zero is summary information describing the number of tracks
       and the total number of minutes on the disk.  Entries 1 through N
       contain information about each individual track.  All position
       information will be in LSN format.

       The io_Data field points to an array of CDTOC structures to receive
       the TOC data.

       The io_Length field specifies the total number of entries to be
       fetched.  The array pointed to by io_Data must be at least this many
       elements in size.

       The io_Offset field specifies the entry number at which to start
       copying TOC data into *io_Data.

       Entry zero (the summary entry) contains the following:

       struct @{"TOCSummary" Link "includes/devices/cd.h/Main" 248} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        FirstTrack;    /* First track on disk (always 1)   */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        LastTrack;     /* Last track on disk               */
           union LSNMSF LeadOut;       /* Beginning of lead-out track      */
           };

       Track entries (entries 1 through number of tracks) contain:

       struct @{"TOCEntry" Link "includes/devices/cd.h/Main" 256} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        CtlAdr;        /* Q-Code info                  */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Track;         /* Track number                 */
           union LSNMSF Position;      /* Start position of this track */
           };

       CDTOC is described as a union between these two structures:

       union CDTOC {

           struct @{"TOCSummary" Link "includes/devices/cd.h/Main" 248} Summary;  /* First entry is summary info.  */
           struct @{"TOCEntry" Link "includes/devices/cd.h/Main" 256}   Entry;    /* Entries 1-N are track entries */
           };


@{b}   EXAMPLE@{ub}
       
       union CDTOC tocarray[100];

       ior->io_Command = CD_TOCLSN;        /* Retrieve TOC information */
       ior->io_Offset  = 0;                /* Start with summary info  */
       ior->io_Length  = 100;              /* Max 99 tracks + summary  */
       ior->io_Data    = (APTR)tocarray;   /* Here's where we want it  */
       @{"DoIO" Link "exec/DoIO()"} (ior);

       if (!ior->io_Error) {               /* Command succeeded        */

           firsttrack   = tocarray[0].Summary.FirstTrack;
           lasttrack    = tocarray[0].Summary.LastTrack;
           totalsectors = tocarray[0].Summary.LeadOut.LSN -
                          tocarray[1].Entry.Position.LSN;
           }

@{b}   NOTES@{ub}

       In the above example, the amount of data on the disk is calculated as
       being equal to the location of the lead-out track minus the start of
       the first track (which is never zero).

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}

@EndNode

@Node "CD_TOCMSF" "cd.device/CD_TOCMSF"

@{b}   NAME@{ub}
       CD_TOCMSF -- Return table of contents information from CD (MSF form).

@{b}   IO REQUEST@{ub}
       io_Device       preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Unit         preset by the call to @{"OpenDevice()" Link "OpenDevice()"}
       io_Command      CD_TOCMSF
       io_Data         pointer to array where TOC is to be stored
       io_Length       number of CDTOC entries to be fetched
       io_Offset       entry to begin at (entry 0 is summary information)

@{b}   RESULTS@{ub}
       io_Error        0 for success, or an error code as defined in
                       @{"<devices/cd.h>" Link "includes/devices/cd.h/Main" 0}
       io_Actual       Actual number of entries copied

@{b}   FUNCTION@{ub}
       This command returns the table of contents of the disk currently in
       the drive.  The table of contents consists of up to 100 entries.
       Entry zero is summary information describing the number of tracks
       and the total number of minutes on the disk.  Entries 1 through N
       contain information about each individual track.  All position
       information will be in MSF format.

       The io_Data field points to an array of CDTOC structures to receive
       the TOC data.

       The io_Length field specifies the total number of entries to be
       fetched.  The array pointed to by io_Data must be at least this many
       elements in size.

       The io_Offset field specifies the entry number at which to start
       copying TOC data into *io_Data.

       Entry zero (the summary entry) contains the following:

       struct @{"TOCSummary" Link "includes/devices/cd.h/Main" 248} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        FirstTrack;    /* First track on disk (always 1)   */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        LastTrack;     /* Last track on disk               */
           union LSNMSF LeadOut;       /* Beginning of lead-out track      */
           };

       Track entries (entries 1 through number of tracks) contain:

       struct @{"TOCEntry" Link "includes/devices/cd.h/Main" 256} {

           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        CtlAdr;        /* Q-Code info                  */
           @{"UBYTE" Link "includes/exec/types.h/Main" 46}        Track;         /* Track number                 */
           union LSNMSF Position;      /* Start position of this track */
           };

       CDTOC is described as a union between these two structures:

       union CDTOC {

           struct @{"TOCSummary" Link "includes/devices/cd.h/Main" 248} Summary;  /* First entry is summary info.  */
           struct @{"TOCEntry" Link "includes/devices/cd.h/Main" 256}   Entry;    /* Entries 1-N are track entries */
           };


@{b}   EXAMPLE@{ub}
       
@{b}   NOTES@{ub}

@{b}   BUGS@{ub}

@{b}   SEE ALSO@{ub}

@EndNode

@Node "CloseDevice()" "cd.device/CloseDevice"

@{b}   NAME@{ub}
       CloseDevice - terminate access to the CD

@{b}   SYNOPSIS@{ub}
       CloseDevice(IORequest);
                   A1

@{b}   FUNCTION@{ub}
       This function will terminate access to the unit openned with
       @{"OpenDevice()" Link "OpenDevice()"}.

@{b}   INPUTS@{ub}
       iORequest - pointer to a struct(IOStdReq)

@{b}   RESULTS@{ub}

@{b}   NOTES@{ub}

@{b}   SEE ALSO@{ub}
       @{"OpenDevice()" Link "OpenDevice()"}

@EndNode

@Node "OpenDevice()" "cd.device/OpenDevice"

@{b}   NAME@{ub}
       OpenDevice - Open a CD unit for access

@{b}   SYNOPSIS@{ub}
       error = OpenDevice("cd.device", UnitNumber, @{"IORequest" Link "includes/exec/io.h/Main" 17}, flags);
       D0                 A0           D0          A1         D1

@{b}   FUNCTION@{ub}
       Opens the cd.device and creates an @{"IORequest" Link "includes/exec/io.h/Main" 17} for use in accessing
       the CD.

@{b}   INPUTS@{ub}
       UnitNumber - Normally zero; however, this is described as:
                    Ones digit      = @{"Unit" Link "includes/exec/devices.h/Main" 30} (SCSI unit number)
                    Tens digit      = LUN (disk within disk changer)
                    Hundreds digit  = Card number (SCSI card)
                    Thousands digit = Reserved (must be zero)
       @{"IORequest" Link "includes/exec/io.h/Main" 17}  - Pointer to a struct(IOStdReq)
       flags      - Should be zero.

@{b}   RESULTS@{ub}
       error        0 = success, otherwise this is an error.

@{b}   NOTES@{ub}

@{b}   SEE ALSO@{ub}
       @{"CloseDevice()" Link "CloseDevice()"}

@EndNode

