#ifndef CD_DEBUG
#define CD_DEBUG 0
#endif

#include ssdef
#include descrip
#include "cdrom.h"
#include "cdrom-data.h"

typedef struct
{
    short length;
    short code;
    void *buffer;
    short *retlenaddr;
} ItemList;

#define BYTE_0(a)  ((a)        & 0x000000ff)
#define BYTE_1(a) (((a) >> 8)  & 0x000000ff)
#define BYTE_2(a) (((a) >> 16) & 0x000000ff)
#define BYTE_3(a) (((a) >> 24) & 0x000000ff)

static short
    channel;

static int
    cd__toc_valid = 0,
    cd__loaded = 0,
    cd__ready = 0,
    cd__changed = 0,
    cd__track_number = 0,
    cd__index_number = 0,
    cd__status = 0,
    cd__tracks = 0,
    cd__debug = CD_DEBUG;

static scsi_read_toc_data
    cd__toc;
static scsi_current_position_data
    cd__cpos;

static struct
{
    scsi_mode_header_6 header;
    scsi_mode_block_descriptor block;
    scsi_param_audio_control page;
}
    cd__audio_control_data,
    cd__audio_control_mask;

int cd_start_time()
{
    if (! cd__toc_valid) cd_read_toc();
    if (! cd__toc_valid) return 0;

    return cd__toc.track[0].absolute_address.msf.m * 60 * 75 +
           cd__toc.track[0].absolute_address.msf.s * 75 +
           cd__toc.track[0].absolute_address.msf.f;
}

int cd_final_time()
{
    int tracks, length, entries, total;

    if (! cd__toc_valid) cd_read_toc();
    if (! cd__toc_valid) return 0;

    length = (cd__toc.header.toc_data_length1 << 8)
            | cd__toc.header.toc_data_length0;
    entries = ((length - 2) / sizeof (scsi_read_toc_track_data)) - 1;

    return cd__toc.track[entries].absolute_address.msf.m * 60 * 75 +
           cd__toc.track[entries].absolute_address.msf.s * 75 +
           cd__toc.track[entries].absolute_address.msf.f - 1;
}

int cd_album_total_time()
{
    return cd_final_time() - cd_start_time();
}


int cd_album_current_time()
{
    if (!(cd_get_status() & 1)) return 0;

    return (cd__cpos.absolute_address.msf.m * 60 * 75) +
           (cd__cpos.absolute_address.msf.s * 75) +
            cd__cpos.absolute_address.msf.f;
}

int cd_album_remaining_time()
{
    return cd_album_total_time() - cd_album_current_time();
}

int cd_song_total_time(int track)
{
    int length, entries, start, end, total;
    int m, s, f, i;

    if (track == 0) track = cd_current_track();

    if (!(cd_get_status() & 1)) return 0;

    length = (cd__toc.header.toc_data_length1 << 8)
            | cd__toc.header.toc_data_length0;
    entries = (length - 2) / sizeof (scsi_read_toc_track_data);

    i = track - 1;
    if (cd__toc.track[i].track_number != track)
    {   /* if it wasn't a simple mapping of tracks, let's look for it. */
        /* mind you, I'm not sure if this sort of thing can happen or not */
        i = 0;
        while((i < entries) && (cd__toc.track[i].track_number != track))
        {
            ++i;
        }
    }

    end = 0;
    if (track == cd__toc.track[i].track_number)
    {
        start = 
            cd__toc.track[i].absolute_address.msf.m * 75 * 60 +
            cd__toc.track[i].absolute_address.msf.s * 75 +
            cd__toc.track[i].absolute_address.msf.f;
        if ((i + 1) < entries)
        {
            end = 
                cd__toc.track[i+1].absolute_address.msf.m * 75 * 60 + 
                cd__toc.track[i+1].absolute_address.msf.s * 75 +
                cd__toc.track[i+1].absolute_address.msf.f;
        }
    }

    return (start < end) ? (end - start) : 0;
}

int cd_song_start_time(int track)
{
    int length, entries, start, i;

    if (track == 0) track = cd_current_track();

    if (!(cd_get_status() & 1)) return 0;

    length = (cd__toc.header.toc_data_length1 << 8)
            | cd__toc.header.toc_data_length0;
    entries = (length - 2) / sizeof (scsi_read_toc_track_data);


    i = track - 1;
    if (cd__toc.track[i].track_number != track)
    {
        i = 0;
        while((i < entries) && (cd__toc.track[i].track_number != track))
        {
            ++i;
        }
    }

    if (track != cd__toc.track[i].track_number)
    {
        return 0;
    }

    return  cd__toc.track[i].absolute_address.msf.m * 60 * 75 +
            cd__toc.track[i].absolute_address.msf.s * 75 +
            cd__toc.track[i].absolute_address.msf.f;
}

int cd_song_current_time()
{
    if (! cd__toc_valid) return 0;

    return cd__cpos.track_relative_address.msf.m * 60 * 75 +
           cd__cpos.track_relative_address.msf.s * 75 +
           cd__cpos.track_relative_address.msf.f;
}

int cd_song_remaining_time()
{
    return cd_song_total_time(0) - cd_song_current_time();
}

int cd_tracks()
{
    if (! cd__toc_valid) cd_read_toc();
    if (! cd__toc_valid) cd__tracks = 0;
    return cd__tracks;
}

int cd_status()
{
    if (! cd_ready()) cd__status = 0;
    return cd__status;
}

int cd_is_playing()
{
    int play_state;

    switch(cd_status())
    {
      case 0x11: /* Audio play operation in progress.            */
        play_state = 1;
        break;
      case 0x12: /* Audio play operation paused - ? so, is it "playing?" */
      default:
        play_state = 0;
        break;
    }
    return play_state;
}

int cd_is_paused()
{
    int pause_state;

    switch(cd_status())
    {
      case 0: /* hmm, disk must not be ready                    */
      case 0x13: /* Audio play operation successfully completed. */
      case 0x14: /* Audio play operation stopped due to error.   */
      case 0x15: /* No current audio status to return            */
      case 0x11: /* Audio play operation in progress.            */
        pause_state = 0;
        break;
      case 0x12: /* Audio play operation paused.                 */
        pause_state = 1;
        break;
    }
    return pause_state;
}

int cd_current_track()
{
    if (! cd_ready()) cd__track_number = 0;
    return cd__track_number;
}

int cd_first_track()
{
    if (! cd__toc_valid) cd_read_toc();
    if (! cd__toc_valid) cd__toc.header.first_track = 0;
    return cd__toc.header.first_track;
}

int cd_last_track()
{
    if (! cd__toc_valid) cd_read_toc();
    if (! cd__toc_valid) cd__toc.header.last_track = 0;
    return cd__toc.header.last_track;
}

int cd_play_frame_to_end(int start_f)
{
    int end_f = cd_final_time();

    return cd_play_msf(start_f / 75 / 60, (start_f / 75) % 60, start_f % 75,
                       end_f / 75 / 60, (end_f / 75) % 60, end_f % 75);
}

int cd_play_frame_to_frame(int start_f, int end_f)
{
    return cd_play_msf(start_f / 75 / 60, (start_f / 75) % 60, start_f % 75,
                       end_f / 75 / 60, (end_f / 75) % 60, end_f % 75);
}

int cd_play_msf
(
    int start_m, int start_s, int start_f,
    int end_m, int end_s, int end_f
)
{
    static scsi_play_audio_msf
        cmd =
        {
            SCSI_PLAY_AUDIO_MSF,    /* opcode */
            0,                      /* reserved */
            0,                      /* lun */
            0,                      /* reserved */
            0, 0, 0,                /* start m/s/f */
            0, 0, 0,                /* end m/s/f */
            0                       /* control */
        };

    cmd.start_m = start_m;
    cmd.start_s = start_s;
    cmd.start_f = start_f;
    cmd.end_m = end_m;
    cmd.end_s = end_s;
    cmd.end_f = end_f;

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_play_track_index
(
    int start_track, int start_index,
    int end_track, int end_index
)
{
    static scsi_play_audio_track_index
        cmd =
        {
            SCSI_PLAY_AUDIO_TRACK_INDEX,    /* opcode */
            0,                              /* reserved */
            0,                              /* lun */
            0, 0,                           /* reserved */
            0, 0,                           /* start track/index */
            0,                              /* reserved */
            0, 0,                           /* end track/index */
            0                               /* control */
        };
    cmd.start_track = start_track;
    cmd.start_index = start_index;
    cmd.end_track = end_track;
    cmd.end_index = end_index;

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_get_status()
{
    static scsi_read_subchannel
        cmd =
        {
            SCSI_READ_SUBCHANNEL,   /* opcode               */
            0,                      /* reserved             */
            1,                      /* msf                  */
            0,                      /* reserved             */
            0,                      /* lun                  */
            0,                      /* reserved             */
            1,                      /* subq                 */
            0,                      /* reserved             */
            0x01,                   /* sub_chan_data_format */
            0, 0,                   /* reserved             */
            0,                      /* track_number         */
            0,                      /* allocation_length1   */
            0,                      /* allocation_length0   */
            0                       /* control              */
        };
    int status;

    status = cd_read_subchannel(&cmd, sizeof cmd, &cd__cpos, sizeof cd__cpos);
    if (status & 1)
    {
        if (cd__loaded == 0)
        {
            cd__loaded = 1; /* odd, this should have happened via check_condition */
        }
        if (cd__ready == 0)
        {
            cd__ready = 1;
        }   /* if (cd__ready == 0) */

        if (cd__changed)
        {   /* the disk was unloaded and reloaded.. */
            cd__changed = 0;
            cd_read_toc();
        }   /* if (cd__changed) */

        cd__status = cd__cpos.audio_status;
        cd__track_number = cd__cpos.track_number;
        cd__index_number = cd__cpos.index_number;
    }   /* if (status & 1) */
    return status;
}   /* cd_get_status() */

int cd_read_subchannel
(
    scsi_read_subchannel *cmd,
    int cmd_len,
    void *data,
    int data_len
)
{   /* attempt to get the current status of the CD player. */
    cmd->allocation_length1 = BYTE_1(data_len);
    cmd->allocation_length0 = BYTE_0(data_len);
    return cd_execute_command(cmd, cmd_len, data, data_len);
}

int cd_loaded()
{
    cd_get_status();
    return cd__loaded;
}

int cd_ready()
{
    if (cd_test_unit_ready())
    {
        cd_get_status();
    }
    else
    {
        cd__ready == 0;
    }
    return cd__ready;
}

int cd_request_sense(scsi_request_sense_data *data, unsigned char length)
{
    static scsi_request_sense
        cmd =
        {
            SCSI_REQUEST_SENSE,     /* opcode */
            0,                      /* reserved */
            0,                      /* lun */
            0, 0,                   /* reserved */
            0,                      /* allocation_length */
            0                       /* control */
        };

    cmd.allocation_length = length;
    return cd_execute_command(&cmd, sizeof cmd, data, length);
}

int cd_inquiry(scsi_inquiry_data *data, unsigned char length)
{
    static scsi_inquiry
        cmd =
        {
            SCSI_INQUIRY,       /* opcode                       */
            0,                  /* enable_vital_product_data    */
            0,                  /* reserved                     */
            0,                  /* lun                          */
            0,                  /* page_code                    */
            0,                  /* reserved                     */
            0,                  /* allocation_length;           */
            0                   /* control                      */
        };

    cmd.allocation_length = length;
    return cd_execute_command(&cmd, sizeof cmd, data, length);
}

int cd_eject()
{
    static scsi_start_stop_unit
        cmd =
        {
            SCSI_START_STOP_UNIT,   /* opcode */
            0,                      /* immediate */
            0,                      /* reserved */
            0,                      /* lun */
            0, 0,                   /* reserved */
            0,                      /* start */
            1,                      /* load_eject */
            0,                      /* reserved */
            0                       /* control */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_start_unit()
{
    static scsi_start_stop_unit
        cmd =
        {
            SCSI_START_STOP_UNIT,   /* opcode */
            0,                      /* immediate */
            0,                      /* reserved */
            0,                      /* lun */
            0, 0,                   /* reserved */
            1,                      /* start */
            0,                      /* load_eject */
            0,                      /* reserved */
            0                       /* control */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_stop_unit()
{
    static scsi_start_stop_unit
        cmd =
        {
            SCSI_START_STOP_UNIT,   /* opcode */
            0,                      /* immediate */
            0,                      /* reserved */
            0,                      /* lun */
            0, 0,                   /* reserved */
            0,                      /* start */
            0,                      /* load_eject */
            0,                      /* reserved */
            0                       /* control */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_lock()
{
    static scsi_prevent_allow_medium_removal
        cmd =
        {
            SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL,      /* opcode   */
            0,                                      /* reserved */
            0,                                      /* lun      */
            0, 0,                                   /* reserved */
            1,                                      /* prevent  */
            0,                                      /* reserved */
            0                                       /* control  */
        };                                          

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_unlock()
{
    static scsi_prevent_allow_medium_removal
        cmd =
        {
            SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL,      /* opcode   */
            0,                                      /* reserved */
            0,                                      /* lun      */
            0, 0,                                   /* reserved */
            0,                                      /* prevent  */
            0,                                      /* reserved */
            0                                       /* control  */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_allocate()
{
    $DESCRIPTOR(player, "DECW$CD_PLAYER");
    scsi_inquiry_data inquiry_data;
    int status;

    status = sys$assign(&player, &channel, 0, 0);
    if (!(status & 1)) return status;

    status = cd_inquiry(&inquiry_data, sizeof inquiry_data);
    if (!(status & 1)) return status;

    if (inquiry_data.device_type != 5) /* cdrom ? */
    {
        printf("This device isn't a CD-ROM?\n");
        return SS$_ABORT;
    }

    return 1;
}

int cd_deallocate()
{
    return sys$dassgn(channel);
}

typedef struct 
{
    unsigned char opcode;
    /* etc.. */
} command;

int cd_execute_command(command *cmd_addr, int cmd_len, int *data_addr, int data_len)
{
#   define FLAGS_READ 1
#   define FLAGS_DISCONNECT 2
    static struct
    {
        int
            opcode,
            flags,
            command_address,
            command_length,
            data_address,
            data_length,
            pad_length,
            phase_timeout,
            disconnect_timeout,
            reserved[6];
    } gk_desc =
        {1, FLAGS_READ + FLAGS_DISCONNECT, 0,0,0,0, 0, 0, 60, 0,0,0,0,0,0};
    globalvalue IO$_DIAGNOSE;
	long int
        i,
        status;
    short int
        gk_iosb[4];
	unsigned char scsi_status;

    gk_desc.command_address = cmd_addr,
    gk_desc.command_length = cmd_len;
    gk_desc.data_address = data_addr;
    gk_desc.data_length = data_len;

	status = sys$qiow (0, channel, IO$_DIAGNOSE, gk_iosb, 0, 0,
			   &gk_desc, sizeof gk_desc, 0, 0, 0, 0);

	if (!(status & 1)) return status;
    status = gk_iosb[0];
	if (!(status & 1)) return status;

    /* change status to low word = 0, high word = scsi status */
    status = (gk_iosb[3] & 0x0000ff00) << 8;

    switch (gk_iosb[3] >> 8)
    {
      case STATUS_GOOD:
        status = 1;
        break;
      case STATUS_CHECK_CONDITION:
        if (cmd_addr->opcode != SCSI_REQUEST_SENSE)
        {   /* we don't want to get recursive here.. */
            cd_check_condition();
        }
        else
        { /* we got a check_condition error on a request sense command. */
/***************************************************************************
  The target shall return CHECK CONDITION status for a REQUEST SENSE command 
only to report errors specific to the command itself.  For example:
  (1) A non-zero reserved bit is detected in the command descriptor block.
  (2) An unrecovered parity error is detected on the data bus. 
  (3) A target malfunction prevents return of the sense data.
***************************************************************************/
            static int recursion_warning = 0;
            if (recursion_warning == 0)
            {
                ++recursion_warning;
                cd_check_condition();
                --recursion_warning;
            }
            else
            {
                printf("Programmer foo-bar'd. Aborting cd_execute_command().\n");
                lib$signal(SS$_ABORT);
            }
        };
        break;
      default:
        break;
    };
	return status;
}

int cd_check_condition()
{
    scsi_request_sense_data sense_data;

    if (!(cd_request_sense(&sense_data, sizeof sense_data) & 1))
    {
        /* why couldn't we? weird. */
        printf("Programmer foo-bar'd. Aborting cd_check_condition().\n");
        lib$signal(SS$_ABORT);
    } /* if (!(cd_request_sense(&sense_data, sizeof sense_data) & 1)) */

#define MEDIUM_NOT_PRESENT 0x3a
#define NOT_READY_TO_READY_TRANSITION 0x28
    switch (sense_data.sense_key)
    {
      case SENSE_KEY_NOT_READY:
        cd__toc_valid = 0;
        cd__ready = 0;
        if (sense_data.asc == MEDIUM_NOT_PRESENT)
        {
            cd__loaded = 0;
        }
        break;
      case SENSE_KEY_UNIT_ATTENTION:
        if (sense_data.asc == NOT_READY_TO_READY_TRANSITION)
        {
            cd__toc_valid = 0;
            cd__changed = 1; /* cd may have changed, assume it did. */
            cd__loaded = 1;
        } /* if (sense_data.adc == NOT_READY_TO_READY_TRANSITION)*/
        break;
    } /* switch (sense_data.sense_key) */

    if (cd__debug) cd__print_sense_key_info(&sense_data);
    return 1;
}

int cd_read_toc()
{
    static scsi_read_toc
        cmd =
        {
            SCSI_READ_TOC,          /* opcode */
            0,                      /* reserved */
            1,                      /* msf format? */
            0,                      /* reserved */
            0,                      /* lun */
            0, 0, 0, 0,             /* reserved */
            0,                      /* starting track */
            BYTE_1(sizeof cd__toc), /* alloc length msb */
            BYTE_0(sizeof cd__toc), /* alloc length lsb */
            0                       /* control */
        };                                  
    int status;                

    /* erase out old contents - just to be safe */
    memset(&cd__toc, 0, sizeof cd__toc);

    status = cd_execute_command(&cmd, sizeof cmd, &cd__toc, sizeof cd__toc);
    if (status & 1)
    {
        /* we have a valid table of contents! */
        /* let's see how many things they passed back...*/
        unsigned int length, entries;

        cd__toc_valid = 1;

        length = (cd__toc.header.toc_data_length1 << 8)
                 | cd__toc.header.toc_data_length0;
        entries = (length - 2) / sizeof (scsi_read_toc_track_data);
        cd__tracks = cd__toc.header.last_track - cd__toc.header.first_track + 1;
    } /* if (status & 1) */
    return status;
}

int cd_change_all_pages()
{
    unsigned char buffer[256];
    int length;

    cd__get_all_pages(buffer, sizeof buffer);

    length = buffer[0];

    /* play with the buffer while in DEBUG here.. what fun! */

    return cd__set_all_pages(buffer, length);
}

cd__get_all_pages(unsigned char *buffer, int length)
{
    static scsi_mode_sense_6
        cmd =
        {
            SCSI_MODE_SENSE_6,              /* opcode */
            0,                              /* reserved */
            0,                              /* dbd */
            0,                              /* reserved */
            0,                              /* lun */
            0x3f,                           /* page_code */
            0,                              /* pc */
            0,                              /* reserved */
            0,                              /* allocation_length */
            0                               /* control */
        };
    
    cmd.allocation_length = length;
    if (cmd.allocation_length == 256) cmd.allocation_length = 0; /* weird huh? */

    return cd_execute_command ( &cmd, sizeof cmd, buffer, length );
}

int cd__set_all_pages(unsigned char *buffer, int length)
{
    static scsi_mode_select_6
        cmd =
        {
            SCSI_MODE_SELECT_6,             /* opcode */
            0,                              /* save page */
            0,                              /* reserved */
            1,                              /* page format */
            0,                              /* lun */
            0, 0,                           /* reserved */
            0,                              /* parameter list length */
            0                               /* control */
        };
    
    cmd.parameter_list_length = length;

    return cd_execute_command ( &cmd, sizeof cmd, buffer, length );
}

int cd__get_audio_control_page()
{
    static scsi_mode_sense_6
        cmd =
        {
            SCSI_MODE_SENSE_6,              /* opcode */
            0,                              /* reserved */
            0,                              /* dbd */
            0,                              /* reserved */
            0,                              /* lun */
            0x0e,                           /* page_code */
            0,                              /* pc */
            0,                              /* reserved */
            sizeof cd__audio_control_data,  /* allocation_length lsb */
            0                               /* control */
        };
    
    return cd_execute_command
    (
        &cmd, sizeof cmd,
        &cd__audio_control_data,
        sizeof cd__audio_control_data
    );
}

int cd__get_audio_control_page_mask()
{
    static scsi_mode_sense_6
        cmd =
        {
            SCSI_MODE_SENSE_6,              /* opcode */
            0,                              /* reserved */
            0,                              /* dbd */
            0,                              /* reserved */
            0,                              /* lun */
            0x0e,                           /* page_code */
            1,                              /* pc */
            0,                              /* reserved */
            sizeof cd__audio_control_mask,  /* allocation_length lsb */
            0                               /* control */
        };
    static int repeat = 0;

    if (! repeat)
    {    
        return cd_execute_command
        (
            &cmd, sizeof cmd,
            &cd__audio_control_mask,
            sizeof cd__audio_control_mask
        );
        ++repeat;
    }
    else
    {
        return 1;
    }
}

int cd_get_volume(int *left, int *right)
{
    int status;

    status = cd__get_audio_control_page();
    if (!(status & 1)) return status;

    *left  = cd__audio_control_data.page.port_0_volume;
    *right = cd__audio_control_data.page.port_1_volume;

    return 1;
}

int cd_set_volume(int left, int right)
{
    static scsi_mode_select_6
        cmd =
        {
            SCSI_MODE_SELECT_6,             /* opcode */
            0,                              /* save page */
            0,                              /* reserved */
            1,                              /* page format */
            0,                              /* lun */
            0, 0,                           /* reserved */
            sizeof cd__audio_control_data,  /* parameter list length */
            0                               /* control */
        };
    int status;

    status = cd__get_audio_control_page();
    if (!(status & 1)) return status;

    cd__audio_control_data.header.mode_data_length = 0;
    cd__audio_control_data.page.port_0_volume = left;
    cd__audio_control_data.page.port_1_volume = right;

    return cd_execute_command
    (
        &cmd, sizeof cmd,
        &cd__audio_control_data,
        sizeof cd__audio_control_data
    );
}

int cd_reserve()
{
    static scsi_reserve
        cmd =
        {
            SCSI_RESERVE,       /* opcode                   */
            0,                  /* extent                   */
            0,                  /* third_party_device_id    */
            0,                  /* third_party              */
            0,                  /* lun                      */
            0,                  /* reservation_id           */
            0,                  /* extent_list_length1      */
            0,                  /* extent_list_length0      */
            0                   /* control                  */
        };                                                
    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_release()
{
    static scsi_release
        cmd =
        {
            SCSI_RELEASE,       /* opcode                   */
            0,                  /* extent                   */
            0,                  /* third_party_device_id    */
            0,                  /* third_party              */
            0,                  /* lun                      */
            0,                  /* reservation_id           */
            0, 0,               /* reserved                 */
            0                   /* control                  */
        };                      
    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_test_unit_ready()
{
    static scsi_test_unit_ready
        cmd =
        {
            SCSI_TEST_UNIT_READY,   /* opcode   */
            0,                      /* reserved */
            0,                      /* lun      */
            0, 0, 0,                /* reserved */
            0                       /* control  */
        };
    int status;

    status = cd_execute_command(&cmd, sizeof cmd, 0, 0);
    if (status & 1)
    {
        cd__ready = 1;
        cd__loaded = 1; /* well, if it's ready, it must be loaded.. */
    }
    return status;
}

int cd_pause()
{
    static scsi_pause_resume
        cmd =
        {
            SCSI_PAUSE_RESUME,  /* opcode   */
            0,                  /* reserved */
            0,                  /* lun      */
            0,0,0,0,0,0,        /* reserved */
            0,                  /* resume   */
            0,                  /* reserved */
            0                   /* control  */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}

int cd_resume()
{
    static scsi_pause_resume
        cmd =
        {
            SCSI_PAUSE_RESUME,  /* opcode   */
            0,                  /* reserved */
            0,                  /* lun      */
            0,0,0,0,0,0,        /* reserved */
            1,                  /* resume   */
            0,                  /* reserved */
            0                   /* control  */
        };

    return cd_execute_command(&cmd, sizeof cmd, 0, 0);
}
