summaryrefslogtreecommitdiff
path: root/wodim/drv_sony.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/drv_sony.c')
-rw-r--r--wodim/drv_sony.c1364
1 files changed, 1364 insertions, 0 deletions
diff --git a/wodim/drv_sony.c b/wodim/drv_sony.c
new file mode 100644
index 0000000..af8af68
--- /dev/null
+++ b/wodim/drv_sony.c
@@ -0,0 +1,1364 @@
+/*
+ * 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);
+}