Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

drv_sony.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)drv_sony.c 1.72 05/05/16 Copyright 1997-2005 J. Schilling */
/*
 *    CDR device implementation for
 *    Sony
 *
 *    Copyright (c) 1997-2005 J. Schilling
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*#define   SONY_DEBUG*/

#include <mconfig.h>

#include <stdio.h>
#include <stdxlib.h>
#include <unixstd.h>    /* Include sys/types.h to make off_t available */
#include <standard.h>
#include <fctldefs.h>
#include <errno.h>
#include <strdefs.h>
#include <timedefs.h>

#include <utypes.h>
#include <btorder.h>
#include <intcvt.h>
#include <schily.h>

#include <usal/usalcmd.h>
#include <usal/scsidefs.h>
#include <usal/scsireg.h>
#include <usal/scsitransp.h>

#include "wodim.h"

#ifdef      SONY_DEBUG
#     define            inc_verbose()     usalp->verbose++
#     define            dec_verbose()     usalp->verbose--
#else
#     define            inc_verbose()
#     define            dec_verbose()
#endif

extern      int   debug;
extern      int   lverbose;

#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */

struct sony_924_mode_page_20 {      /* mastering information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x06 = 6 Bytes */
      Uchar subcode_header_off;
      Ucbit res3_0            : 1;
      Ucbit speudo            : 1;
      Ucbit res3_2            : 1;
      Ucbit c2po        : 1;
      Ucbit subcode_ecc : 1;
      Ucbit res3_567    : 3;
      Uchar res_4;
      Uchar cue_sheet_opt;
      Uchar res[2];
};

#else                   /* Motorola byteorder */

struct sony_924_mode_page_20 {      /* mastering information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x06 = 6 Bytes */
      Uchar subcode_header_off;
      Ucbit res3_567    : 3;
      Ucbit subcode_ecc : 1;
      Ucbit c2po        : 1;
      Ucbit res3_2            : 1;
      Ucbit speudo            : 1;
      Ucbit res3_0            : 1;
      Uchar res_4;
      Uchar cue_sheet_opt;
      Uchar res[2];
};
#endif

struct sony_924_mode_page_22 {      /* disk information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x1E = 30 Bytes */
      Uchar disk_style;
      Uchar disk_type;
      Uchar first_track;
      Uchar last_track;
      Uchar numsess;
      Uchar res_7;
      Uchar disk_appl_code[4];
      Uchar last_start_time[4];
      Uchar disk_status;
      Uchar num_valid_nra;
      Uchar track_info_track;
      Uchar post_gap;
      Uchar disk_id_code[4];
      Uchar lead_in_start[4];
      Uchar res[4];
};

struct sony_924_mode_page_23 {      /* track information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x22 = 34 Bytes */
      Uchar res_2;
      Uchar track_num;
      Uchar data_form;
      Uchar write_method;
      Uchar session;
      Uchar track_status;
      Uchar start_lba[4];
      Uchar next_recordable_addr[4];
      Uchar blank_area_cap[4];
      Uchar fixed_packet_size[4];
      Uchar res_24;
      Uchar starting_msf[3];
      Uchar res_28;
      Uchar ending_msf[3];
      Uchar res_32;
      Uchar next_rec_time[3];
};

struct sony_924_mode_page_31 {      /* drive speed */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x02 = 2 Bytes */
      Uchar speed;
      Uchar res;
};

struct cdd_52x_mode_data {
      struct scsi_mode_header header;
      union cdd_pagex   {
            struct sony_924_mode_page_20  page_s20;
            struct sony_924_mode_page_22  page_s22;
            struct sony_924_mode_page_23  page_s23;
            struct sony_924_mode_page_31  page_s31;
      } pagex;
};

struct sony_write_parameter {
      Uchar res0;             /* Reserved (must be zero)    */
      Uchar len;              /* Parameter length 0x32 == 52      */
      Uchar res2;             /* Reserved (must be zero)    */
#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
      Ucbit res3_05           : 6;  /* Reserved             */
      Ucbit ms          : 2;  /* Multi session mode         */
#else                   /* Motorola byteorder */
      Ucbit ms          : 2;  /* Multi session mode         */
      Ucbit res3_05           : 6;  /* Reserved             */
#endif
      Uchar resx[12];
#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
      Ucbit res16_06    : 7;  /* Reserved             */
      Ucbit mcval       : 1;  /* MCN valid                  */
#else                   /* Motorola byteorder */
      Ucbit mcval       : 1;  /* MCN valid                  */
      Ucbit res16_06    : 7;  /* Reserved             */
#endif
      Uchar mcn[15];
#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
      Ucbit res32_06    : 7;  /* Reserved             */
      Ucbit icval       : 1;  /* ISRC valid                 */
#else                   /* Motorola byteorder */
      Ucbit icval       : 1;  /* ISRC valid                 */
      Ucbit res32_06    : 7;  /* Reserved             */
#endif
      Uchar isrc[15];
      Uchar subheader[4];
};

struct sony_cue {
      Uchar cs_ctladr;        /* CTL/ADR for this track     */
      Uchar cs_tno;                 /* This track number          */
      Uchar cs_index;         /* Index within this track    */
      Uchar cs_dataform;            /* Data form                  */
                              /* Bit 0..5 Main channel Format     */
                              /* Bit 6..7 SubChannel format */
      Uchar cs_zero;          /* Reserved or MCN/ISRC       */
      Uchar cs_min;                 /* Absolute time minutes      */
      Uchar cs_sec;                 /* Absolute time seconds      */
      Uchar cs_frame;         /* Absolute time frames       */
};


#define     strbeg(s1, s2)    (strstr((s2), (s1)) == (s2))

static      int   write_start_sony(SCSI *usalp, caddr_t bp, int size);
static      int   write_continue_sony(SCSI *usalp, caddr_t bp, long sectaddr, 
                                                                    long size, int blocks, BOOL islast);
static      int   discontinue_sony(SCSI *usalp);
static      int   write_track_sony(SCSI *usalp, long track, int sectype);
static      int   close_track_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   flush_sony(SCSI *usalp, int track);
static      int   finalize_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   recover_sony(SCSI *usalp, cdr_t *dp, int track);
static      int   set_wr_parameter_sony(SCSI *usalp, caddr_t bp, int size);
static      int   next_wr_addr_sony(SCSI *usalp, track_t *trackp, long *ap);
static      int   reserve_track_sony(SCSI *usalp, unsigned long len);
static      int   init_sony(SCSI *usalp, cdr_t *dp);
static      int   getdisktype_sony(SCSI *usalp, cdr_t *dp);
static      void  di_to_dstat_sony(struct sony_924_mode_page_22 *dip, 
                                                              dstat_t *dsp);
static      int   speed_select_sony(SCSI *usalp, cdr_t *dp, int *speedp);
static      int   next_writable_address_sony(SCSI *usalp, long *ap, int track, 
                                                                                    int sectype, int tracktype);
static      int   new_track_sony(SCSI *usalp, int track, int sectype, 
                                                            int tracktype);
static      int   open_track_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   open_session_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   abort_session_sony(SCSI *usalp, cdr_t *dp);
static      int   get_page22_sony(SCSI *usalp, char *mode);
static      int   gen_cue_sony(track_t *trackp, void *vcuep, BOOL needgap);
static      void  fillcue(struct sony_cue *cp, int ca, int tno, int idx, int dataform, int scms, msf_t *mp);
static      int   send_cue_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   write_leadin_sony(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   sony_attach(SCSI *usalp, cdr_t *dp);
#ifdef      SONY_DEBUG
static      void  print_sony_mp22(struct sony_924_mode_page_22 *xp, int len);
static      void  print_sony_mp23(struct sony_924_mode_page_23 *xp, int len);
#endif
static      int   buf_cap_sony(SCSI *usalp, long *, long *);

cdr_t cdr_sony_cdu924 = {
      0, 0,
      CDR_TAO|CDR_SAO|CDR_CADDYLOAD|CDR_SWABAUDIO,
      CDR_CDRW_NONE,
      2, 4,
      "sony_cdu924",
      "driver for Sony CDU-924 / CDU-948",
      0,
      (dstat_t *)0,
      drive_identify,
      sony_attach,
      init_sony,
      getdisktype_sony,
      scsi_load,
      scsi_unload,
      buf_cap_sony,
      cmd_dummy,                          /* recovery_needed */
      recover_sony,
      speed_select_sony,
      select_secsize,
      next_wr_addr_sony,
      reserve_track_sony,
      write_continue_sony,
      gen_cue_sony,
      send_cue_sony,
      write_leadin_sony,
      open_track_sony,
      close_track_sony,
      open_session_sony,
      cmd_dummy,
      abort_session_sony,
      read_session_offset_philips,
      finalize_sony,
      cmd_dummy,                          /* stats    */
      blank_dummy,
      format_dummy,
      (int(*)(SCSI *, caddr_t, int, int))NULL,  /* no OPC   */
      cmd_dummy,                          /* opt1           */
      cmd_dummy,                          /* opt2           */
};

static int
write_start_sony(SCSI *usalp, caddr_t bp, int size)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = bp;
      scmd->size = size;
      scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->sense_len = 26;
      scmd->cdb.g1_cdb.cmd = 0xE0;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      g0_cdbaddr(&scmd->cdb.g0_cdb, size); /* Hack, but Sony is silly */

      usalp->cmdname = "write_start";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
write_continue_sony(SCSI *usalp, 
                    caddr_t bp      /* address of buffer */, 
                    long sectaddr   /* disk address (sector) to put */, 
                    long size       /* number of bytes to transfer */, 
                    int blocks      /* sector count */, 
                    BOOL islast     /* last write for track */)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = bp;
      scmd->size = size;
      scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE1;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      g0_cdbaddr(&scmd->cdb.g0_cdb, size); /* Hack, but Sony is silly */

      usalp->cmdname = "write_continue";

      if (usal_cmd(usalp) < 0) {
            /*
             * XXX This seems to happen only sometimes.
             */
            if (usal_sense_code(usalp) != 0x80)
                  return (-1);
      }
      return (size - usal_getresid(usalp));
}

static int
discontinue_sony(SCSI *usalp)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE2;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);

      usalp->cmdname = "discontinue";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
write_track_sony(SCSI *usalp, 
                 long track     /* track number 0 == new track */, 
                 int sectype    /* no sectype for Sony write track */)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xF5;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      g1_cdbaddr(&scmd->cdb.g1_cdb, track);

      usalp->cmdname = "write_track";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

/* XXX NOCH NICHT FERTIG */
static int
close_track_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      register struct   usal_cmd    *scmd = usalp->scmd;
      int   track = 0;

      if (!is_tao(trackp) && !is_packet(trackp))
            return (0);

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xF0;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      g1_cdbaddr(&scmd->cdb.g1_cdb, track);
/* XXX Padding ??? (bit 0 in addr[0] / CDB[2]) */

      usalp->cmdname = "close_track";

      if (usal_cmd(usalp) < 0)
            return (-1);

      /*
       * Clear the silly "error situation" from Sony´ dummy write end
       * but notify if real errors occurred.
       */
      usalp->silent++;
      if (test_unit_ready(usalp) < 0 && usal_sense_code(usalp) != 0xD4) {
            usalp->cmdname = "close_track/test_unit_ready";
            usal_printerr(usalp);
      }
      usalp->silent--;

      return (0);
}

static int
finalize_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      register struct   usal_cmd    *scmd = usalp->scmd;
      int   dummy = track_base(trackp)->tracktype & TOCF_DUMMY;

      if (!is_tao(trackp) && !is_packet(trackp)) {
            wait_unit_ready(usalp, 240);
            return (0);
      }
      if (dummy) {
            printf("Fixating is not possible in dummy write mode.\n");
            return (0);
      }
      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->timeout = 8 * 60;       /* Needs up to 4 minutes */
      scmd->cdb.g1_cdb.cmd = 0xF1;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.g1_cdb.count[1] = ((track_base(trackp)->tracktype & TOCF_MULTI) ? 1 : 0);
/* XXX Padding ??? (bit 0 in addr[0] / CDB[2]) */

      usalp->cmdname = "finalize";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
flush_sony(SCSI *usalp, int track)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->timeout = 8 * 60;       /* Needs up to 4 minutes */
      scmd->cdb.g1_cdb.cmd = 0xF2;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[5] = track;
/* XXX POE ???       (bit 1 in addr[0] / CDB[2]) */
/* XXX Padding ??? (bit 0 in addr[0] / CDB[2]) */
/* XXX Partial flush ??? (CDB[3]) */

      usalp->cmdname = "flush";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
recover_sony(SCSI *usalp, cdr_t *dp, int track)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xF6;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.g1_cdb.addr[3] = track;

      usalp->cmdname = "recover";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
set_wr_parameter_sony(SCSI *usalp, caddr_t bp, int size)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = bp;
      scmd->size = size;
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xF8;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      g1_cdblen(&scmd->cdb.g1_cdb, size);

      usalp->cmdname = "set_write_parameter";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
next_wr_addr_sony(SCSI *usalp, track_t *trackp, long *ap)
{
      if (next_writable_address_sony(usalp, ap, 0, 0, 0) < 0)
            return (-1);
      return (0);
}

static int
reserve_track_sony(SCSI *usalp, unsigned long len)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xF3;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], len);

      usalp->cmdname = "reserve_track";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int
init_sony(SCSI *usalp, cdr_t *dp)
{
      return (speed_select_sony(usalp, dp, NULL));
}


#define     IS(what, flag)    printf("  Is %s%s\n", flag?"":"not ", what);

static int
getdisktype_sony(SCSI *usalp, cdr_t *dp)
{
      dstat_t     *dsp = dp->cdr_dstat;
      long  dummy;
      long  lst;
      msf_t msf;

      char              mode[256];
      struct scsi_mode_page_header  *mp;
      struct sony_924_mode_page_22  *xp;

      dummy = get_page22_sony(usalp, mode);
      if (dummy >= 0) {
            mp = (struct scsi_mode_page_header *)
                  (mode + sizeof (struct scsi_mode_header) +
                  ((struct scsi_mode_header *)mode)->blockdesc_len);

            xp = (struct sony_924_mode_page_22 *)mp;

            if (xp->disk_appl_code[0] == 0xFF)
                  dummy = -1;
      } else {
            return (drive_getdisktype(usalp, dp));
      }

      if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0 && dummy >= 0) {

            printf("ATIP info from disk:\n");
            printf("  Indicated writing power: %d\n",
                        (unsigned)(xp->disk_appl_code[1] & 0x70) >> 4);
            IS("unrestricted", xp->disk_appl_code[2] & 0x40);
            printf("  Disk application code: %d\n", xp->disk_appl_code[2] & 0x3F);
            msf.msf_min = xp->lead_in_start[1];
            msf.msf_sec = xp->lead_in_start[2];
            msf.msf_frame = xp->lead_in_start[3];
            lst = msf_to_lba(msf.msf_min, msf.msf_sec, msf.msf_frame, FALSE);
            if (lst  < -150) {
                  /*
                   * The Sony CDU 920 seems to deliver 00:00/00 for
                   * lead-in start time, dont use it.
                   */
                  printf("  ATIP start of lead in:  %ld (%02d:%02d/%02d)\n",
                        msf_to_lba(msf.msf_min, msf.msf_sec, msf.msf_frame, FALSE),
                        msf.msf_min, msf.msf_sec, msf.msf_frame);
            }
            msf.msf_min = xp->last_start_time[1];
            msf.msf_sec = xp->last_start_time[2];
            msf.msf_frame = xp->last_start_time[3];
            printf("  ATIP start of lead out: %ld (%02d:%02d/%02d)\n",
                  msf_to_lba(msf.msf_min, msf.msf_sec, msf.msf_frame, TRUE),
                  msf.msf_min, msf.msf_sec, msf.msf_frame);
            if (lst  < -150) {
                  /*
                   * The Sony CDU 920 seems to deliver 00:00/00 for
                   * lead-in start time, dont use it.
                   */
                  msf.msf_min = xp->lead_in_start[1];
                  msf.msf_sec = xp->lead_in_start[2];
                  msf.msf_frame = xp->lead_in_start[3];
                  pr_manufacturer(&msf,
                              FALSE,      /* Always not erasable */
                              (xp->disk_appl_code[2] & 0x40) != 0);
            }
      }
      if (dummy >= 0)
            di_to_dstat_sony(xp, dsp);
      return (drive_getdisktype(usalp, dp));
}

static void
di_to_dstat_sony(struct sony_924_mode_page_22 *dip, dstat_t *dsp)
{
      msf_t msf;

      dsp->ds_diskid = a_to_u_4_byte(dip->disk_id_code);
#ifdef      PROTOTYPES
      if (dsp->ds_diskid != 0xFFFFFFFFUL)
#else
      if (dsp->ds_diskid != (Ulong)0xFFFFFFFF)
#endif
            dsp->ds_flags |= DSF_DID_V;
      dsp->ds_diskstat = (dip->disk_status >> 6) & 0x03;
#ifdef      XXX
      /*
       * There seems to be no MMC equivalent...
       */
      dsp->ds_sessstat = dip->sess_status;
#endif

      dsp->ds_maxblocks = msf_to_lba(dip->last_start_time[1],
                              dip->last_start_time[2],
                              dip->last_start_time[3], TRUE);
      /*
       * Check for 0xFF:0xFF/0xFF which is an indicator for a complete disk
       */
      if (dsp->ds_maxblocks == 716730)
            dsp->ds_maxblocks = -1L;

      if (dsp->ds_first_leadin == 0) {
            dsp->ds_first_leadin = msf_to_lba(dip->lead_in_start[1],
                                    dip->lead_in_start[2],
                                    dip->lead_in_start[3], FALSE);
            /*
             * Check for illegal values (> 0)
             * or for empty field (-150) with CDU-920.
             */
            if (dsp->ds_first_leadin > 0 || dsp->ds_first_leadin == -150)
                  dsp->ds_first_leadin = 0;
      }

      if (dsp->ds_last_leadout == 0 && dsp->ds_maxblocks >= 0)
            dsp->ds_last_leadout = dsp->ds_maxblocks;

      msf.msf_min = dip->lead_in_start[1];
      msf.msf_sec = dip->lead_in_start[2];
      msf.msf_frame = dip->lead_in_start[3];
      dsp->ds_maxrblocks = disk_rcap(&msf, dsp->ds_maxblocks,
                              FALSE,      /* Always not erasable */
                              (dip->disk_appl_code[2] & 0x40) != 0);
}


int   sony_speeds[] = {
            -1,         /* Speed null is not allowed */
            0,          /* Single speed */
            1,          /* Double speed */
            -1,         /* Three times */
            3,          /* Quad speed */
};

static int
speed_select_sony(SCSI *usalp, cdr_t *dp, int *speedp)
{
      struct cdd_52x_mode_data md;
      int   count;
      int   err;
      int   speed = 1;
      BOOL  dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;

      if (speedp) {
            speed = *speedp;
            if (speed < 1 || speed > 4 || sony_speeds[speed] < 0)
                  return (-1);
      }

      fillbytes((caddr_t)&md, sizeof (md), '\0');

      count  = sizeof (struct scsi_mode_header) +
            sizeof (struct sony_924_mode_page_20);

      md.pagex.page_s20.p_code = 0x20;
      md.pagex.page_s20.p_len =  0x06;
      md.pagex.page_s20.speudo = dummy?1:0;

      /*
       * Set Cue sheet option. This is documented for the 924 and
       * seems to be supported for the 948 too.
       */
      md.pagex.page_s20.cue_sheet_opt = 0x03;

      err = mode_select(usalp, (Uchar *)&md, count, 0, 1);
      if (err < 0)
            return (err);

      if (speedp == 0)
            return (0);

      fillbytes((caddr_t)&md, sizeof (md), '\0');

      count  = sizeof (struct scsi_mode_header) +
            sizeof (struct sony_924_mode_page_31);

      md.pagex.page_s31.p_code = 0x31;
      md.pagex.page_s31.p_len =  0x02;
      md.pagex.page_s31.speed = sony_speeds[speed];

      return (mode_select(usalp, (Uchar *)&md, count, 0, 1));
}

static int
next_writable_address_sony(SCSI *usalp, long *ap, int track, int sectype, 
                           int tracktype)
{
      struct      scsi_mode_page_header *mp;
      char              mode[256];
      int               len = 0x30;
      int               page = 0x23;
      struct sony_924_mode_page_23  *xp;

      fillbytes((caddr_t)mode, sizeof (mode), '\0');

      inc_verbose();
      if (!get_mode_params(usalp, page, "CD track information",
                  (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
            dec_verbose();
            return (-1);
      }
      dec_verbose();
      if (len == 0)
            return (-1);

      mp = (struct scsi_mode_page_header *)
            (mode + sizeof (struct scsi_mode_header) +
            ((struct scsi_mode_header *)mode)->blockdesc_len);


      xp = (struct sony_924_mode_page_23 *)mp;

#ifdef      SONY_DEBUG
      print_sony_mp23(xp, len);
#endif
      if (ap)
            *ap = a_to_4_byte(xp->next_recordable_addr);
      return (0);
}


static int
new_track_sony(SCSI *usalp, int track, int sectype, int tracktype)
{
      struct      scsi_mode_page_header *mp;
      char              mode[256];
      int               len = 0x30;
      int               page = 0x23;
      struct sony_924_mode_page_23  *xp;
      int   i;

      fillbytes((caddr_t)mode, sizeof (mode), '\0');
      get_page22_sony(usalp, mode);

      fillbytes((caddr_t)mode, sizeof (mode), '\0');

      inc_verbose();
      if (!get_mode_params(usalp, page, "CD track information",
                  (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
            dec_verbose();
            return (-1);
      }
      dec_verbose();
      if (len == 0)
            return (-1);

      mp = (struct scsi_mode_page_header *)
            (mode + sizeof (struct scsi_mode_header) +
            ((struct scsi_mode_header *)mode)->blockdesc_len);


      xp = (struct sony_924_mode_page_23 *)mp;

#ifdef      SONY_DEBUG
      print_sony_mp23(xp, len);
#endif

      xp->write_method = 0;   /* Track at one recording */

      if (sectype & ST_AUDIOMASK) {
            xp->data_form = (sectype & ST_MASK) == ST_AUDIO_PRE ? 0x02 : 0x00;
      } else {
            if (tracktype == TOC_ROM) {
                  xp->data_form = (sectype & ST_MASK) == ST_ROM_MODE1 ? 0x10 : 0x11;
            } else if (tracktype == TOC_XA1) {
                  xp->data_form = 0x12;
            } else if (tracktype == TOC_XA2) {
                  xp->data_form = 0x12;
            } else if (tracktype == TOC_CDI) {
                  xp->data_form = 0x12;
            }
      }

      ((struct scsi_modesel_header *)mode)->sense_data_len  = 0;
      ((struct scsi_modesel_header *)mode)->res2            = 0;

      i = ((struct scsi_mode_header *)mode)->blockdesc_len;
      if (i > 0) {
            i_to_3_byte(
                  ((struct scsi_mode_data *)mode)->blockdesc.nlblock,
                                                0);
      }

      if (mode_select(usalp, (Uchar *)mode, len, 0, usalp->inq->data_format >= 2) < 0) {
            return (-1);
      }

      return (0);
}

static int
open_track_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      if (!is_tao(trackp) && !is_packet(trackp)) {
            if (trackp->pregapsize > 0 && (trackp->flags & TI_PREGAP) == 0) {
                  if (lverbose) {
                        printf("Writing pregap for track %d at %ld\n",
                              (int)trackp->trackno,
                              trackp->trackstart-trackp->pregapsize);
                  }
                  /*
                   * XXX Do we need to check isecsize too?
                   */
                  pad_track(usalp, dp, trackp,
                        trackp->trackstart-trackp->pregapsize,
                        (Llong)trackp->pregapsize*trackp->secsize,
                              FALSE, 0);
            }
            return (0);
      }

      if (select_secsize(usalp, trackp->secsize) < 0)
            return (-1);

      if (new_track_sony(usalp, trackp->trackno, trackp->sectype, trackp->tracktype & TOC_MASK) < 0)
            return (-1);

      if (write_track_sony(usalp, 0L, trackp->sectype) < 0)
            return (-1);

      return (0);
}

static int
open_session_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      struct      scsi_mode_page_header *mp;
      char              mode[256];
      int   i;
      int   len = 0x30;
      struct sony_924_mode_page_22  *xp;

      fillbytes((caddr_t)mode, sizeof (mode), '\0');

      if ((len = get_page22_sony(usalp, mode)) < 0)
            return (-1);

      mp = (struct scsi_mode_page_header *)
            (mode + sizeof (struct scsi_mode_header) +
            ((struct scsi_mode_header *)mode)->blockdesc_len);

      xp = (struct sony_924_mode_page_22 *)mp;

      xp->disk_type = toc2sess[track_base(trackp)->tracktype & TOC_MASK];

      if (is_tao(track_base(trackp))) {
#ifdef      __needed__
            if ((track_base(trackp)->tracktype & TOC_MASK) == TOC_DA)
                  xp->disk_style = 0x80;
            else
                  xp->disk_style = 0xC0;
#endif
      } else if (is_sao(track_base(trackp))) {
            /*
             * We may only change this value if the disk is empty.
             * i.e. when disk_status & 0xC0 == 0x00
             */
            if ((xp->disk_status & 0xC0) != 0) {
                  if (xp->disk_style != 0x00)
                        errmsgno(EX_BAD, "Cannot change disk stile for recorded disk.\n");
            }
            xp->disk_style = 0x00;
      }

      ((struct scsi_modesel_header *)mode)->sense_data_len  = 0;
      ((struct scsi_modesel_header *)mode)->res2            = 0;

      i = ((struct scsi_mode_header *)mode)->blockdesc_len;
      if (i > 0) {
            i_to_3_byte(
                  ((struct scsi_mode_data *)mode)->blockdesc.nlblock,
                                                0);
      }

      if (mode_select(usalp, (Uchar *)mode, len, 0, usalp->inq->data_format >= 2) < 0) {
            return (-1);
      }
/*
 * XXX set write parameter für SAO mit Multi Session (948 only?)
 * XXX set_wr_parameter_sony(usalp, bp, size);
 */
      return (0);
}

static int
abort_session_sony(SCSI *usalp, cdr_t *dp)
{
      return (discontinue_sony(usalp));
}

static int
get_page22_sony(SCSI *usalp, char *mode)
{
      struct      scsi_mode_page_header *mp;
      int   len = 0x30;
      int   page = 0x22;
      struct sony_924_mode_page_22  *xp;

      fillbytes((caddr_t)mode, sizeof (mode), '\0');

      inc_verbose();
      if (!get_mode_params(usalp, page, "CD disk information",
                  (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
            dec_verbose();
            return (-1);
      }
      dec_verbose();
      if (len == 0)
            return (-1);

      mp = (struct scsi_mode_page_header *)
            (mode + sizeof (struct scsi_mode_header) +
            ((struct scsi_mode_header *)mode)->blockdesc_len);

      xp = (struct sony_924_mode_page_22 *)mp;

#ifdef      SONY_DEBUG
      print_sony_mp22(xp, len);
#endif
      return (len);
}

/*--------------------------------------------------------------------------*/

static Uchar      db2df[] = {
      0x01,             /*  0 2352 bytes of raw data              */
      0xFF,             /*  1 2368 bytes (raw data + P/Q Subchannel)    */
      0xFF,             /*  2 2448 bytes (raw data + P-W Subchannel)    */
      0xFF,             /*  3 2448 bytes (raw data + P-W raw Subchannel)*/
      0xFF,             /*  4 -    Reserved                       */
      0xFF,             /*  5 -    Reserved                       */
      0xFF,             /*  6 -    Reserved                       */
      0xFF,             /*  7 -    Vendor specific                */
      0x11,             /*  8 2048 bytes Mode 1 (ISO/IEC 10149)         */
      0xFF,             /*  9 2336 bytes Mode 2 (ISO/IEC 10149)         */
      0xFF,             /* 10 2048 bytes Mode 2! (CD-ROM XA form 1)     */
      0xFF,             /* 11 2056 bytes Mode 2 (CD-ROM XA form 1)      */
      0xFF,             /* 12 2324 bytes Mode 2 (CD-ROM XA form 2)      */
      0xFF,             /* 13 2332 bytes Mode 2 (CD-ROM XA 1/2+subhdr)  */
      0xFF,             /* 14 -    Reserved                       */
      0xFF,             /* 15 -    Vendor specific                */
};

static int
gen_cue_sony(track_t *trackp, void *vcuep, BOOL needgap)
{
      int   tracks = trackp->tracks;
      int   i;
      struct sony_cue   **cuep = vcuep;
      struct sony_cue   *cue;
      struct sony_cue   *cp;
      int   ncue = 0;
      int   icue = 0;
      int   pgsize;
      msf_t m;
      int   ctl;
      int   df;
      int   scms;

      cue = malloc(1);

      for (i = 0; i <= tracks; i++) {
            ctl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
            if (is_copy(&trackp[i]))
                  ctl |= TM_ALLOW_COPY << 4;
            df = db2df[trackp[i].dbtype & 0x0F];

#ifdef      __supported__
            if (trackp[i].isrc) {   /* MCN or ISRC */
                  ncue += 2;
                  cue = realloc(cue, ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  if (i == 0) {
                        cp->cs_ctladr = 0x02;
                        movebytes(&trackp[i].isrc[0], &cp->cs_tno, 7);
                        cp = &cue[icue++];
                        cp->cs_ctladr = 0x02;
                        movebytes(&trackp[i].isrc[7], &cp->cs_tno, 7);
                  } else {
                        cp->cs_ctladr = 0x03;
                        cp->cs_tno = i;
                        movebytes(&trackp[i].isrc[0], &cp->cs_index, 6);
                        cp = &cue[icue++];
                        cp->cs_ctladr = 0x03;
                        cp->cs_tno = i;
                        movebytes(&trackp[i].isrc[6], &cp->cs_index, 6);
                  }
            }
#endif
            if (i == 0) {     /* Lead in */
                  df &= ~7;
                  if (trackp[0].flags & TI_TEXT)      /* CD-Text in Lead-in*/
                        df |= 0xC0;
                  lba_to_msf(-150, &m);
                  cue = realloc(cue, ++ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  fillcue(cp, ctl|0x01, i, 0, df, 0, &m);
            } else {
                  scms = 0;

                  if (is_scms(&trackp[i]))
                        scms = 0x80;
                  pgsize = trackp[i].pregapsize;
                  if (pgsize == 0 && needgap)
                        pgsize++;
                  lba_to_msf(trackp[i].trackstart-pgsize, &m);
                  cue = realloc(cue, ++ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  fillcue(cp, ctl|0x01, i, 0, df, scms, &m);

                  if (trackp[i].nindex == 1) {
                        lba_to_msf(trackp[i].trackstart, &m);
                        cue = realloc(cue, ++ncue * sizeof (*cue));
                        cp = &cue[icue++];
                        fillcue(cp, ctl|0x01, i, 1, df, scms, &m);
                  } else {
                        int   idx;
                        long  *idxlist;

                        ncue += trackp[i].nindex;
                        idxlist = trackp[i].tindex;
                        cue = realloc(cue, ncue * sizeof (*cue));

                        for (idx = 1; idx <= trackp[i].nindex; idx++) {
                              lba_to_msf(trackp[i].trackstart + idxlist[idx], &m);
                              cp = &cue[icue++];
                              fillcue(cp, ctl|0x01, i, idx, df, scms, &m);
                        }
                  }
            }
      }
      /* Lead out */
      ctl = (st2mode[trackp[tracks+1].sectype & ST_MASK]) << 4;
      df = db2df[trackp[tracks+1].dbtype & 0x0F];
      df &= ~7;
      lba_to_msf(trackp[tracks+1].trackstart, &m);
      cue = realloc(cue, ++ncue * sizeof (*cue));
      cp = &cue[icue++];
      fillcue(cp, ctl|0x01, 0xAA, 1, df, 0, &m);

      if (lverbose > 1) {
            for (i = 0; i < ncue; i++) {
                  usal_prbytes("", (Uchar *)&cue[i], 8);
            }
      }
      if (cuep)
            *cuep = cue;
      else
            free(cue);
      return (ncue);
}


static void
fillcue(struct sony_cue *cp     /* The target cue entry */, 
        int ca                  /* Control/adr for this entry */, 
        int tno                 /* Track number for this entry */, 
        int idx                 /* Index for this entry */, 
        int dataform            /* Data format for this entry */, 
        int scms                /* Serial copy management */, 
        msf_t *mp               /* MSF value for this entry */)
{
      cp->cs_ctladr = ca;
      if (tno <= 99)
            cp->cs_tno = to_bcd(tno);
      else
            cp->cs_tno = tno;
      cp->cs_index = to_bcd(idx);
      cp->cs_dataform = dataform;
      cp->cs_zero = scms;
      cp->cs_min = to_bcd(mp->msf_min);
      cp->cs_sec = to_bcd(mp->msf_sec);
      cp->cs_frame = to_bcd(mp->msf_frame);
}

static int
send_cue_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      struct sony_cue *cp;
      int         ncue;
      int         ret;
      Uint        i;
      struct timeval starttime;
      struct timeval stoptime;
      int         disktype;

      disktype = toc2sess[track_base(trackp)->tracktype & TOC_MASK];

      for (i = 1; i <= trackp->tracks; i++) {
            if (trackp[i].tracksize < (tsize_t)0) {
                  errmsgno(EX_BAD, "Track %d has unknown length.\n", i);
                  return (-1);
            }
      }
      ncue = (*dp->cdr_gen_cue)(trackp, &cp, FALSE);

      starttime.tv_sec = 0;
      starttime.tv_usec = 0;
      stoptime = starttime;
      gettimeofday(&starttime, (struct timezone *)0);

      usalp->silent++;
      ret  = write_start_sony(usalp, (caddr_t)cp, ncue*8);
      usalp->silent--;
      free(cp);
      if (ret < 0) {
            errmsgno(EX_BAD, "CUE sheet not accepted. Retrying with minimum pregapsize = 1.\n");
            ncue = (*dp->cdr_gen_cue)(trackp, &cp, TRUE);
            ret  = write_start_sony(usalp, (caddr_t)cp, ncue*8);
            free(cp);
      }
      if (ret >= 0 && lverbose) {
            gettimeofday(&stoptime, (struct timezone *)0);
            prtimediff("Write Lead-in time: ", &starttime, &stoptime);
      }
      return (ret);
}

static int
write_leadin_sony(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      Uint  i;
      long  startsec = 0L;

/*    if (flags & F_SAO) {*/
      if (wm_base(dp->cdr_dstat->ds_wrmode) == WM_SAO) {
            if (debug || lverbose) {
                  printf("Sending CUE sheet...\n");
                  flush();
            }
            if (trackp[0].flags & TI_TEXT) {
                  if (dp->cdr_speeddef != 4) {
                        errmsgno(EX_BAD,
                        "The CDU-924 does not support CD-Text, disabling.\n");

                        trackp[0].flags &= ~TI_TEXT;
                  }
            }
            if ((*dp->cdr_send_cue)(usalp, dp, trackp) < 0) {
                  errmsgno(EX_BAD, "Cannot send CUE sheet.\n");
                  return (-1);
            }

            if (trackp[0].flags & TI_TEXT) {
                  startsec = dp->cdr_dstat->ds_first_leadin;
                  printf("SAO startsec: %ld\n", startsec);
            } else {
                  startsec = -150;
            }
            if (debug)
                  printf("SAO startsec: %ld\n", startsec);

            if (trackp[0].flags & TI_TEXT) {
                  if (startsec > 0) {
                        errmsgno(EX_BAD, "CD-Text must be in first session.\n");
                        return (-1);
                  }
                  if (debug || lverbose)
                        printf("Writing lead-in...\n");
                  if (write_cdtext(usalp, dp, startsec) < 0)
                        return (-1);

                  dp->cdr_dstat->ds_cdrflags |= RF_LEADIN;
            } else for (i = 1; i <= trackp->tracks; i++) {
                  trackp[i].trackstart += startsec +150;
            }
      }
      return (0);
}

/*--------------------------------------------------------------------------*/

static const char *sd_cdu_924_error_str[] = {

      "\200\000write complete",                       /* 80 00 */
      "\201\000logical unit is reserved",             /* 81 00 */
      "\205\000audio address not valid",              /* 85 00 */
      "\210\000illegal cue sheet",                    /* 88 00 */
      "\211\000inappropriate command",                /* 89 00 */

      "\266\000media load mechanism failed",                /* B6 00 */
      "\271\000audio play operation aborted",               /* B9 00 */
      "\277\000buffer overflow for read all subcodes command", /* BF 00 */
      "\300\000unrecordable disk",                    /* C0 00 */
      "\301\000illegal track status",                       /* C1 00 */
      "\302\000reserved track present",               /* C2 00 */
      "\303\000buffer data size error",               /* C3 00 */
      "\304\001illegal data form for reserve track command",      /* C4 01 */
      "\304\002unable to reserve track, because track mode has been changed", /* C4 02 */
      "\305\000buffer error during at once recording",      /* C5 00 */
      "\306\001unwritten area encountered",                 /* C6 01 */
      "\306\002link blocks encountered",              /* C6 02 */
      "\306\003nonexistent block encountered",        /* C6 03 */
      "\307\000disk style mismatch",                        /* C7 00 */
      "\310\000no table of contents",                       /* C8 00 */
      "\311\000illegal block length for write command",     /* C9 00 */
      "\312\000power calibration error",              /* CA 00 */
      "\313\000write error",                          /* CB 00 */
      "\313\001write error track recovered",                /* CB 01 */
      "\314\000not enough space",                     /* CC 00 */
      "\315\000no track present to finalize",               /* CD 00 */
      "\316\000unrecoverable track descriptor encountered", /* CE 00 */
      "\317\000damaged track present",                /* CF 00 */
      "\320\000pma area full",                        /* D0 00 */
      "\321\000pca area full",                        /* D1 00 */
      "\322\000unrecoverable damaged track cause too small writing area",     /* D2 00 */
      "\323\000no bar code",                          /* D3 00 */
      "\323\001not enough bar code margin",                 /* D3 01 */
      "\323\002no bar code start pattern",                  /* D3 02 */
      "\323\003illegal bar code length",              /* D3 03 */
      "\323\004illegal bar code format",              /* D3 04 */
      "\324\000exit from pseudo track at once recording",   /* D4 00 */
      NULL
};

static int
sony_attach(SCSI *usalp, cdr_t *dp)
{
      if (usalp->inq != NULL) {
            if (strbeg("CD-R   CDU94", usalp->inq->prod_ident)) {
                  dp->cdr_speeddef = 4;
            }
      }
      usal_setnonstderrs(usalp, sd_cdu_924_error_str);
      return (0);
}

#ifdef      SONY_DEBUG
static void
print_sony_mp22(struct sony_924_mode_page_22 *xp, int len)
{
      printf("disk style: %X\n", xp->disk_style);
      printf("disk type: %X\n", xp->disk_type);
      printf("first track: %X\n", xp->first_track);
      printf("last track: %X\n", xp->last_track);
      printf("numsess:    %X\n", xp->numsess);
      printf("disk appl code: %lX\n", a_to_u_4_byte(xp->disk_appl_code));
      printf("last start time: %lX\n", a_to_u_4_byte(xp->last_start_time));
      printf("disk status: %X\n", xp->disk_status);
      printf("num valid nra: %X\n", xp->num_valid_nra);
      printf("track info track: %X\n", xp->track_info_track);
      printf("post gap: %X\n", xp->post_gap);
      printf("disk id code: %lX\n", a_to_u_4_byte(xp->disk_id_code));
      printf("lead in start: %lX\n", a_to_u_4_byte(xp->lead_in_start));
}

static void
print_sony_mp23(struct sony_924_mode_page_23 *xp, int len)
{
      printf("len: %d\n", len);

      printf("track num: %X\n", xp->track_num);
      printf("data form: %X\n", xp->data_form);
      printf("write method: %X\n", xp->write_method);
      printf("session: %X\n", xp->session);
      printf("track status: %X\n", xp->track_status);

/*
 * XXX Check for signed/unsigned a_to_*() conversion.
 */
      printf("start lba: %lX\n", a_to_4_byte(xp->start_lba));
      printf("next recordable addr: %lX\n", a_to_4_byte(xp->next_recordable_addr));
      printf("blank area cap: %lX\n", a_to_u_4_byte(xp->blank_area_cap));
      printf("fixed packet size: %lX\n", a_to_u_4_byte(xp->fixed_packet_size));
      printf("starting msf: %lX\n", a_to_u_4_byte(xp->starting_msf));
      printf("ending msf: %lX\n", a_to_u_4_byte(xp->ending_msf));
      printf("next rec time: %lX\n", a_to_u_4_byte(xp->next_rec_time));
}
#endif

static int
buf_cap_sony(SCSI *usalp, long *sp, long *fp)
{
      char  resp[8];
      Ulong freespace;
      Ulong bufsize;
      int   per;
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = (caddr_t)resp;
      scmd->size = sizeof (resp);
      scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xEC;        /* Read buffer cap */
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);

      usalp->cmdname = "read buffer cap sony";

      if (usal_cmd(usalp) < 0)
            return (-1);

      bufsize   = a_to_u_3_byte(&resp[1]);
      freespace = a_to_u_3_byte(&resp[5]);
      if (sp)
            *sp = bufsize;
      if (fp)
            *fp = freespace;

      if (usalp->verbose || (sp == 0 && fp == 0))
            printf("BFree: %ld K BSize: %ld K\n", freespace >> 10, bufsize >> 10);

      if (bufsize == 0)
            return (0);
      per = (100 * (bufsize - freespace)) / bufsize;
      if (per < 0)
            return (0);
      if (per > 100)
            return (100);
      return (per);
}

Generated by  Doxygen 1.6.0   Back to index