summaryrefslogtreecommitdiff
path: root/wodim/drv_mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/drv_mmc.c')
-rw-r--r--wodim/drv_mmc.c4362
1 files changed, 4362 insertions, 0 deletions
diff --git a/wodim/drv_mmc.c b/wodim/drv_mmc.c
new file mode 100644
index 0000000..b075889
--- /dev/null
+++ b/wodim/drv_mmc.c
@@ -0,0 +1,4362 @@
+/*
+ * 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_mmc.c 1.163 06/01/12 Copyright 1997-2006 J. Schilling */
+/*
+ * CDR device implementation for
+ * SCSI-3/mmc conforming drives
+ * e.g. Yamaha CDR-400, Ricoh MP6200
+ *
+ * Copyright (c) 1997-2006 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 DEBUG*/
+#define PRINT_ATIP
+#include <mconfig.h>
+
+#include <stdio.h>
+#include <standard.h>
+#include <fctldefs.h>
+#include <errno.h>
+#include <strdefs.h>
+#include <stdxlib.h>
+#include <unixstd.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 "scsimmc.h"
+#include "mmcvendor.h"
+#include "wodim.h"
+#include "scsi_scan.h"
+
+extern char *driveropts;
+
+extern int debug;
+extern int lverbose;
+extern int xdebug;
+
+static int curspeed = 1;
+
+static char clv_to_speed[16] = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static char hs_clv_to_speed[16] = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static char us_clv_to_speed[16] = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ 0, 2, 4, 8, 0, 0, 16, 0, 24, 32, 40, 48, 0, 0, 0, 0
+};
+
+#ifdef __needed__
+static int mmc_load(SCSI *usalp, cdr_t *dp);
+static int mmc_unload(SCSI *usalp, cdr_t *dp);
+#endif
+void mmc_opthelp(cdr_t *dp, int excode);
+char *hasdrvopt(char *optstr, char *optname);
+static cdr_t *identify_mmc(SCSI *usalp, cdr_t *, struct scsi_inquiry *);
+static int attach_mmc(SCSI *usalp, cdr_t *);
+static int attach_mdvd(SCSI *usalp, cdr_t *);
+int check_writemodes_mmc(SCSI *usalp, cdr_t *dp);
+int check_writemodes_mdvd(SCSI *usalp, cdr_t *dp);
+static int deflt_writemodes_mmc(SCSI *usalp, BOOL reset_dummy);
+static int deflt_writemodes_mdvd(SCSI *usalp, BOOL reset_dummy);
+static int get_diskinfo(SCSI *usalp, struct disk_info *dip);
+static void di_to_dstat(struct disk_info *dip, dstat_t *dsp);
+static int get_atip(SCSI *usalp, struct atipinfo *atp);
+#ifdef PRINT_ATIP
+static int get_pma(SCSI *usalp);
+#endif
+static int init_mmc(SCSI *usalp, cdr_t *dp);
+static int getdisktype_mmc(SCSI *usalp, cdr_t *dp);
+static int getdisktype_mdvd(SCSI *usalp, cdr_t *dp);
+static int speed_select_mmc(SCSI *usalp, cdr_t *dp, int *speedp);
+static int speed_select_mdvd(SCSI *usalp, cdr_t *dp, int *speedp);
+static int mmc_set_speed(SCSI *usalp, int readspeed, int writespeed,
+ int rotctl);
+static int next_wr_addr_mmc(SCSI *usalp, track_t *trackp, long *ap);
+static int next_wr_addr_mdvd(SCSI *usalp, track_t *trackp, long *ap);
+static int write_leadin_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int open_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int open_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int close_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int close_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int open_session_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int open_session_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int waitfix_mmc(SCSI *usalp, int secs);
+static int fixate_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int fixate_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int blank_mmc(SCSI *usalp, cdr_t *dp, long addr, int blanktype);
+static int format_mdvd(SCSI *usalp, cdr_t *dp, int formattype);
+static int send_opc_mmc(SCSI *usalp, caddr_t, int cnt, int doopc);
+static int opt1_mmc(SCSI *usalp, cdr_t *dp);
+static int opt1_mdvd(SCSI *usalp, cdr_t *dp);
+static int opt2_mmc(SCSI *usalp, cdr_t *dp);
+static int scsi_sony_write(SCSI *usalp, caddr_t bp, long sectaddr, long size,
+ int blocks, BOOL islast);
+static int gen_cue_mmc(track_t *trackp, void *vcuep, BOOL needgap);
+static void fillcue(struct mmc_cue *cp, int ca, int tno, int idx, int dataform,
+ int scms, msf_t *mp);
+static int send_cue_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int stats_mmc(SCSI *usalp, cdr_t *dp);
+static BOOL mmc_isplextor(SCSI *usalp);
+static BOOL mmc_isyamaha(SCSI *usalp);
+static void do_varirec_plextor(SCSI *usalp);
+static int do_gigarec_plextor(SCSI *usalp);
+static int drivemode_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode,
+ void *modeval);
+static int drivemode2_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode,
+ void *modeval);
+static int check_varirec_plextor(SCSI *usalp);
+static int check_gigarec_plextor(SCSI *usalp);
+static int varirec_plextor(SCSI *usalp, BOOL on, int val);
+static int gigarec_plextor(SCSI *usalp, int val);
+static Int32_t gigarec_mult(int code, Int32_t val);
+static int check_ss_hide_plextor(SCSI *usalp);
+static int check_speed_rd_plextor(SCSI *usalp);
+static int check_powerrec_plextor(SCSI *usalp);
+static int ss_hide_plextor(SCSI *usalp, BOOL do_ss, BOOL do_hide);
+static int speed_rd_plextor(SCSI *usalp, BOOL do_speedrd);
+static int powerrec_plextor(SCSI *usalp, BOOL do_powerrec);
+static int get_speeds_plextor(SCSI *usalp, int *selp, int *maxp, int *lastp);
+static int bpc_plextor(SCSI *usalp, int mode, int *bpp);
+static int set_audiomaster_yamaha(SCSI *usalp, cdr_t *dp, BOOL keep_mode);
+
+struct ricoh_mode_page_30 * get_justlink_ricoh(SCSI *usalp, Uchar *mode);
+static int force_speed_yamaha(SCSI *usalp, int readspeed, int writespeed);
+static BOOL get_tattoo_yamaha(SCSI *usalp, BOOL print, Int32_t *irp,
+ Int32_t *orp);
+static int do_tattoo_yamaha(SCSI *usalp, FILE *f);
+static int yamaha_write_buffer(SCSI *usalp, int mode, int bufferid, long offset,
+ long parlen, void *buffer, long buflen);
+static int dvd_dual_layer_split(SCSI *usalp, cdr_t *dp, long tsize);
+
+extern int reserve_track(SCSI *usalp, Ulong size); /* FIXME */
+extern int scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background); /* FIXME */
+
+#ifdef __needed__
+static int
+mmc_load(SCSI *usalp, cdr_t *dp)
+{
+ return (scsi_load_unload(usalp, 1));
+}
+
+static int
+mmc_unload(SCSI *usalp, cdr_t *dp)
+{
+ return (scsi_load_unload(usalp, 0));
+}
+#endif
+
+/*
+ * MMC CD-writer
+ */
+cdr_t cdr_mmc = {
+ 0, 0,
+ CDR_SWABAUDIO,
+ CDR_CDRW_ALL,
+ 372, 372,
+ "mmc_cdr",
+ "generic SCSI-3/mmc CD-R/CD-RW driver",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ attach_mmc,
+ init_mmc,
+ getdisktype_mmc,
+ scsi_load,
+ scsi_unload,
+ read_buff_cap,
+ cmd_dummy, /* check_recovery */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ speed_select_mmc,
+ select_secsize,
+ next_wr_addr_mmc,
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_cdr_write,
+ gen_cue_mmc,
+ send_cue_mmc,
+ write_leadin_mmc,
+ open_track_mmc,
+ close_track_mmc,
+ open_session_mmc,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset,
+ fixate_mmc,
+ stats_mmc,
+ blank_mmc,
+ format_dummy,
+ send_opc_mmc,
+ opt1_mmc,
+ opt2_mmc,
+};
+
+cdr_t cdr_mdvd = {
+ 0, 0,
+ CDR_SWABAUDIO,
+ CDR_CDRW_ALL,
+ 370,370,
+ "mmc_mdvd",
+ "generic SCSI-3/mmc DVD-R(W) driver",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ attach_mdvd,
+ init_mmc,
+ getdisktype_mdvd,
+ scsi_load,
+ scsi_unload,
+ read_buff_cap,
+ cmd_dummy, /* check_recovery */
+ (int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy, /* recover */
+ speed_select_mdvd,
+ select_secsize,
+ next_wr_addr_mdvd,
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_cdr_write,
+ (int(*)__PR((track_t *, void *, BOOL)))cmd_dummy, /* gen_cue */
+ (int(*)__PR((SCSI *usalp, cdr_t *, track_t *)))cmd_dummy, /* send_cue */
+ write_leadin_mmc,
+ open_track_mdvd,
+ close_track_mdvd,
+ open_session_mdvd,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset,
+ fixate_mdvd,
+ stats_mmc,
+ blank_mmc,
+ format_mdvd,
+ send_opc_mmc,
+ opt1_mdvd,
+ opt2_mmc,
+ dvd_dual_layer_split,
+};
+
+/*
+ * Sony MMC CD-writer
+ */
+cdr_t cdr_mmc_sony = {
+ 0, 0,
+ CDR_SWABAUDIO,
+ CDR_CDRW_ALL,
+ 372, 372,
+ "mmc_cdr_sony",
+ "generic SCSI-3/mmc CD-R/CD-RW driver (Sony 928 variant)",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ attach_mmc,
+ init_mmc,
+ getdisktype_mmc,
+ scsi_load,
+ scsi_unload,
+ read_buff_cap,
+ cmd_dummy, /* check_recovery */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ speed_select_mmc,
+ select_secsize,
+ next_wr_addr_mmc,
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_sony_write,
+ gen_cue_mmc,
+ send_cue_mmc,
+ write_leadin_mmc,
+ open_track_mmc,
+ close_track_mmc,
+ open_session_mmc,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset,
+ fixate_mmc,
+ cmd_dummy, /* stats */
+ blank_mmc,
+ format_dummy,
+ send_opc_mmc,
+ opt1_mmc,
+ opt2_mmc,
+};
+
+/*
+ * SCSI-3/mmc conformant CD-ROM drive
+ */
+cdr_t cdr_cd = {
+ 0, 0,
+ CDR_ISREADER|CDR_SWABAUDIO,
+ CDR_CDRW_NONE,
+ 372, 372,
+ "mmc_cd",
+ "generic SCSI-3/mmc CD-ROM driver",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ attach_mmc,
+ cmd_dummy,
+ drive_getdisktype,
+ scsi_load,
+ scsi_unload,
+ read_buff_cap,
+ cmd_dummy, /* check_recovery */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ speed_select_mmc,
+ select_secsize,
+ (int(*)(SCSI *usalp, track_t *, long *))cmd_ill, /* next_wr_addr */
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_cdr_write,
+ (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */
+ no_sendcue,
+ (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */
+ open_track_mmc,
+ close_track_mmc,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */
+ cmd_dummy, /* stats */
+ blank_dummy,
+ format_dummy,
+ (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
+ cmd_dummy, /* opt1 */
+ cmd_dummy, /* opt2 */
+};
+
+/*
+ * Old pre SCSI-3/mmc CD drive
+ */
+cdr_t cdr_oldcd = {
+ 0, 0,
+ CDR_ISREADER,
+ CDR_CDRW_NONE,
+ 372, 372,
+ "scsi2_cd",
+ "generic SCSI-2 CD-ROM driver",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ drive_attach,
+ cmd_dummy,
+ drive_getdisktype,
+ scsi_load,
+ scsi_unload,
+ buf_dummy,
+ cmd_dummy, /* check_recovery */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ speed_select_mmc,
+ select_secsize,
+ (int(*)(SCSI *usal, track_t *, long *))cmd_ill, /* next_wr_addr */
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_cdr_write,
+ (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */
+ no_sendcue,
+ (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */
+ open_track_mmc,
+ close_track_mmc,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset_philips,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */
+ cmd_dummy, /* stats */
+ blank_dummy,
+ format_dummy,
+ (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
+ cmd_dummy, /* opt1 */
+ cmd_dummy, /* opt2 */
+};
+
+/*
+ * SCSI-3/mmc conformant CD or DVD writer
+ * Checks the current medium and then returns either cdr_mmc or cdr_dvd
+ */
+cdr_t cdr_cd_dvd = {
+ 0, 0,
+ CDR_SWABAUDIO,
+ CDR_CDRW_ALL,
+ 372, 372,
+ "mmc_cd_dvd",
+ "generic SCSI-3/mmc CD/DVD driver (checks media)",
+ 0,
+ (dstat_t *)0,
+ identify_mmc,
+ attach_mmc,
+ cmd_dummy,
+ drive_getdisktype,
+ scsi_load,
+ scsi_unload,
+ read_buff_cap,
+ cmd_dummy, /* check_recovery */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ speed_select_mmc,
+ select_secsize,
+ (int(*)(SCSI *usalp, track_t *, long *))cmd_ill, /* next_wr_addr */
+ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
+ scsi_cdr_write,
+ (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */
+ no_sendcue,
+ (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */
+ open_track_mmc,
+ close_track_mmc,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy,
+ cmd_dummy,
+ cmd_dummy, /* abort */
+ read_session_offset,
+ (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */
+ cmd_dummy, /* stats */
+ blank_dummy,
+ format_dummy,
+ (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
+ cmd_dummy, /* opt1 */
+ cmd_dummy, /* opt2 */
+};
+
+void
+mmc_opthelp(cdr_t *dp, int excode)
+{
+ BOOL haveopts = FALSE;
+
+ fprintf(stderr, "Driver options:\n");
+ if (dp->cdr_flags & CDR_BURNFREE) {
+ fprintf(stderr, "burnfree Prepare writer to use BURN-Free technology\n");
+ fprintf(stderr, "noburnfree Disable using BURN-Free technology\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_VARIREC) {
+ fprintf(stderr, "varirec=val Set VariRec Laserpower to -2, -1, 0, 1, 2\n");
+ fprintf(stderr, " Only works for audio and if speed is set to 4\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_GIGAREC) {
+ fprintf(stderr, "gigarec=val Set GigaRec capacity ratio to 0.6, 0.7, 0.8, 1.0, 1.2, 1.3, 1.4\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_AUDIOMASTER) {
+ fprintf(stderr, "audiomaster Turn Audio Master feature on (SAO CD-R Audio/Data only)\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_FORCESPEED) {
+ fprintf(stderr, "forcespeed Tell the drive to force speed even for low quality media\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_SPEEDREAD) {
+ fprintf(stderr, "speedread Tell the drive to read as fast as possible\n");
+ fprintf(stderr, "nospeedread Disable to read as fast as possible\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_DISKTATTOO) {
+ fprintf(stderr, "tattooinfo Print image size info for DiskT@2 feature\n");
+ fprintf(stderr, "tattoofile=name Use 'name' as DiskT@2 image file\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_SINGLESESS) {
+ fprintf(stderr, "singlesession Tell the drive to behave as single session only drive\n");
+ fprintf(stderr, "nosinglesession Disable single session only mode\n");
+ haveopts = TRUE;
+ }
+ if (dp->cdr_flags & CDR_HIDE_CDR) {
+ fprintf(stderr, "hidecdr Tell the drive to hide CD-R media\n");
+ fprintf(stderr, "nohidecdr Disable hiding CD-R media\n");
+ haveopts = TRUE;
+ }
+ if (!haveopts) {
+ fprintf(stderr, "None supported for this drive.\n");
+ }
+ exit(excode);
+}
+
+char *
+hasdrvopt(char *optstr, char *optname)
+{
+ char *ep;
+ char *np;
+ char *ret = NULL;
+ int optnamelen;
+ int optlen;
+ BOOL not = FALSE;
+
+ if (optstr == NULL)
+ return (ret);
+
+ optnamelen = strlen(optname);
+
+ while (*optstr) {
+ not = FALSE; /* Reset before every token */
+ if ((ep = strchr(optstr, ',')) != NULL) {
+ optlen = ep - optstr;
+ np = &ep[1];
+ } else {
+ optlen = strlen(optstr);
+ np = &optstr[optlen];
+ }
+ if ((ep = strchr(optstr, '=')) != NULL) {
+ if (ep < np)
+ optlen = ep - optstr;
+ }
+ if (optstr[0] == '!') {
+ optstr++;
+ optlen--;
+ not = TRUE;
+ }
+ if (strncmp(optstr, "no", 2) == 0) {
+ optstr += 2;
+ optlen -= 2;
+ not = TRUE;
+ }
+ if (strncmp(optstr, optname, optlen) == 0) {
+ ret = &optstr[optlen];
+ break;
+ }
+ optstr = np;
+ }
+ if (ret != NULL) {
+ if (*ret == ',' || *ret == '\0') {
+ if (not)
+ return ("0");
+ return ("1");
+ }
+ if (*ret == '=') {
+ if (not)
+ return (NULL);
+ return (++ret);
+ }
+ }
+ return (ret);
+}
+
+static cdr_t *
+identify_mmc(SCSI *usalp, cdr_t *dp, struct scsi_inquiry *ip)
+{
+ BOOL cdrr = FALSE; /* Read CD-R */
+ BOOL cdwr = FALSE; /* Write CD-R */
+ BOOL cdrrw = FALSE; /* Read CD-RW */
+ BOOL cdwrw = FALSE; /* Write CD-RW */
+ BOOL dvdwr = FALSE; /* DVD writer */
+ BOOL is_dvd = FALSE; /* use DVD driver*/
+ Uchar mode[0x100];
+ struct cd_mode_page_2A *mp;
+ int profile;
+
+ if (ip->type != INQ_WORM && ip->type != INQ_ROMD)
+ return ((cdr_t *)0);
+
+ allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */
+
+ usalp->silent++;
+ mp = mmc_cap(usalp, mode); /* Get MMC capabilities */
+ usalp->silent--;
+ if (mp == NULL)
+ return (&cdr_oldcd); /* Pre SCSI-3/mmc drive */
+
+ /*
+ * At this point we know that we have a SCSI-3/mmc compliant drive.
+ * Unfortunately ATAPI drives violate the SCSI spec in returning
+ * a response data format of '1' which from the SCSI spec would
+ * tell us not to use the "PF" bit in mode select. As ATAPI drives
+ * require the "PF" bit to be set, we 'correct' the inquiry data.
+ *
+ * XXX xxx_identify() should not have any side_effects ??
+ */
+ if (ip->data_format < 2)
+ ip->data_format = 2;
+
+ /*
+ * First handle exceptions....
+ */
+ if (strncmp(ip->vendor_info, "SONY", 4) == 0 &&
+ strncmp(ip->prod_ident, "CD-R CDU928E", 14) == 0) {
+ return (&cdr_mmc_sony);
+ }
+
+ /*
+ * Now try to do it the MMC-3 way....
+ */
+ profile = get_curprofile(usalp);
+ if (xdebug)
+ printf("Current profile: 0x%04X\n", profile);
+ if (profile == 0) {
+ if (xdebug)
+ print_profiles(usalp);
+ /*
+ * If the current profile is 0x0000, then the
+ * drive does not know about the media. First
+ * close the tray and then try to issue the
+ * get_curprofile() command again.
+ */
+ usalp->silent++;
+ load_media(usalp, dp, FALSE);
+ usalp->silent--;
+ profile = get_curprofile(usalp);
+ scsi_prevent_removal(usalp, 0);
+ if (xdebug)
+ printf("Current profile: 0x%04X\n", profile);
+ }
+ if (profile >= 0) {
+ if (lverbose)
+ print_profiles(usalp);
+ if (profile == 0 || (profile >= 0x10 && profile <= 0x15) || profile > 0x19) {
+ /*
+ * 10h DVD-ROM
+ * 11h DVD-R
+ * 12h DVD-RAM
+ * 13h DVD-RW (Restricted overwrite)
+ * 14h DVD-RW (Sequential recording)
+ * 1Ah DVD+RW
+ * 1Bh DVD+R
+ * 2Bh DVD+R DL
+ *
+ */
+ if (profile == 0x11 || profile == 0x13 || profile == 0x14 || profile == 0x1A || profile == 0x1B || profile == 0x2B) {
+ is_dvd = TRUE;
+ dp = &cdr_mdvd;
+ } else {
+ is_dvd = FALSE;
+ dp = &cdr_cd;
+
+ if (profile == 0) { /* No Medium */
+ BOOL is_cdr = FALSE;
+
+ /*
+ * Check for CD-writer
+ */
+ get_wproflist(usalp, &is_cdr, NULL,
+ NULL, NULL);
+ if (is_cdr)
+ return (&cdr_mmc);
+ /*
+ * Other MMC-3 drive without media
+ */
+ return (dp);
+ } if (profile == 0x12) { /* DVD-RAM */
+ errmsgno(EX_BAD,
+ "Found unsupported DVD-RAM media.\n");
+ return (dp);
+ }
+ }
+ }
+ } else {
+ if (xdebug)
+ printf("Drive is pre MMC-3\n");
+ }
+
+ mmc_getval(mp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL, &dvdwr);
+
+ if (!cdwr && !cdwrw) { /* SCSI-3/mmc CD drive */
+ /*
+ * If the drive does not support to write CD's, we select the
+ * CD-ROM driver here. If we have DVD-R/DVD-RW support compiled
+ * in, we may later decide to switch to the DVD driver.
+ */
+ dp = &cdr_cd;
+ } else {
+ /*
+ * We need to set the driver to cdr_mmc because we may come
+ * here with driver set to cdr_cd_dvd which is not a driver
+ * that may be used for actual CD/DVD writing.
+ */
+ dp = &cdr_mmc;
+ }
+
+/*#define DVD_DEBUG*/
+#ifdef DVD_DEBUG
+ if (1) { /* Always check for DVD media in debug mode */
+#else
+ if ((cdwr || cdwrw) && dvdwr) {
+#endif
+ char xb[32];
+
+#ifndef DVD_DEBUG
+ usalp->silent++;
+#else
+ fprintf(stderr, "identify_dvd: checking for DVD media\n");
+#endif
+ if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) {
+ /*
+ * If read DVD structure is supported and works, then
+ * we must have a DVD media in the drive. Signal to
+ * use the DVD driver.
+ */
+ is_dvd = TRUE;
+ } else {
+ if (usal_sense_key(usalp) == SC_NOT_READY) {
+ /*
+ * If the SCSI sense key is NOT READY, then the
+ * drive does not know about the media. First
+ * close the tray and then try to issue the
+ * read_dvd_structure() command again.
+ */
+ load_media(usalp, dp, FALSE);
+ if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) {
+ is_dvd = TRUE;
+ }
+ scsi_prevent_removal(usalp, 0);
+ }
+ }
+#ifndef DVD_DEBUG
+ usalp->silent--;
+#else
+ fprintf(stderr, "identify_dvd: is_dvd: %d\n", is_dvd);
+#endif
+ }
+ if (is_dvd) {
+ if(lverbose>2)
+ fprintf(stderr, "Found DVD media: using cdr_mdvd.\n");
+ dp = &cdr_mdvd;
+ }
+ dp->profile = profile;
+ dp->is_dvd = is_dvd;
+ return (dp);
+}
+
+static int
+attach_mmc(SCSI *usalp, cdr_t *dp)
+{
+ int ret;
+ Uchar mode[0x100];
+ struct cd_mode_page_2A *mp;
+ struct ricoh_mode_page_30 *rp = NULL;
+
+ allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */
+
+ usalp->silent++;
+ mp = mmc_cap(usalp, NULL); /* Get MMC capabilities in allocated mp */
+ usalp->silent--;
+ if (mp == NULL)
+ return (-1); /* Pre SCSI-3/mmc drive */
+
+ dp->cdr_cdcap = mp; /* Store MMC cap pointer */
+
+ dp->cdr_dstat->ds_dr_max_rspeed = a_to_u_2_byte(mp->max_read_speed)/176;
+ if (dp->cdr_dstat->ds_dr_max_rspeed == 0)
+ dp->cdr_dstat->ds_dr_max_rspeed = 372;
+ dp->cdr_dstat->ds_dr_cur_rspeed = a_to_u_2_byte(mp->cur_read_speed)/176;
+ if (dp->cdr_dstat->ds_dr_cur_rspeed == 0)
+ dp->cdr_dstat->ds_dr_cur_rspeed = 372;
+
+ dp->cdr_dstat->ds_dr_max_wspeed = a_to_u_2_byte(mp->max_write_speed)/176;
+ if (mp->p_len >= 28)
+ dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->v3_cur_write_speed)/176;
+ else
+ dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->cur_write_speed)/176;
+
+ if (dp->cdr_speedmax > dp->cdr_dstat->ds_dr_max_wspeed)
+ dp->cdr_speedmax = dp->cdr_dstat->ds_dr_max_wspeed;
+
+ if (dp->cdr_speeddef > dp->cdr_speedmax)
+ dp->cdr_speeddef = dp->cdr_speedmax;
+
+ rp = get_justlink_ricoh(usalp, mode);
+
+ if (mp->p_len >= 28)
+ dp->cdr_flags |= CDR_MMC3;
+ if (mp->p_len >= 24)
+ dp->cdr_flags |= CDR_MMC2;
+ dp->cdr_flags |= CDR_MMC;
+
+ if (mp->loading_type == LT_TRAY)
+ dp->cdr_flags |= CDR_TRAYLOAD;
+ else if (mp->loading_type == LT_CADDY)
+ dp->cdr_flags |= CDR_CADDYLOAD;
+
+ if (mp->BUF != 0) {
+ dp->cdr_flags |= CDR_BURNFREE;
+ } else if (rp) {
+ if ((dp->cdr_cmdflags & F_DUMMY) && rp->TWBFS && rp->BUEFS)
+ dp->cdr_flags |= CDR_BURNFREE;
+
+ if (rp->BUEFS)
+ dp->cdr_flags |= CDR_BURNFREE;
+ }
+
+ if (mmc_isplextor(usalp)) {
+ if (check_varirec_plextor(usalp) >= 0)
+ dp->cdr_flags |= CDR_VARIREC;
+
+ if (check_gigarec_plextor(usalp) >= 0)
+ dp->cdr_flags |= CDR_GIGAREC;
+
+ if (check_ss_hide_plextor(usalp) >= 0)
+ dp->cdr_flags |= CDR_SINGLESESS|CDR_HIDE_CDR;
+
+ if (check_powerrec_plextor(usalp) >= 0)
+ dp->cdr_flags |= CDR_FORCESPEED;
+
+ if (check_speed_rd_plextor(usalp) >= 0)
+ dp->cdr_flags |= CDR_SPEEDREAD;
+ }
+ if (mmc_isyamaha(usalp)) {
+ if (set_audiomaster_yamaha(usalp, dp, FALSE) >= 0)
+ dp->cdr_flags |= CDR_AUDIOMASTER;
+
+ /*
+ * Starting with CRW 2200 / CRW 3200
+ */
+ if ((mp->p_len+2) >= (unsigned)28)
+ dp->cdr_flags |= CDR_FORCESPEED;
+
+ if (get_tattoo_yamaha(usalp, FALSE, 0, 0))
+ dp->cdr_flags |= CDR_DISKTATTOO;
+ }
+
+ if (rp && rp->AWSCS)
+ dp->cdr_flags |= CDR_FORCESPEED;
+
+#ifdef FUTURE_ROTCTL
+ if (mp->p_len >= 28) {
+ int val;
+
+ val = dp->cdr_dstat->ds_dr_cur_wspeed;
+ if (val == 0)
+ val = 372;
+
+ usalp->verbose++;
+ if (scsi_set_speed(usalp, -1, val, ROTCTL_CAV) < 0) {
+ fprintf(stderr, "XXX\n");
+ }
+ usalp->verbose--;
+ }
+#endif
+
+ check_writemodes_mmc(usalp, dp);
+
+ /* Enable Burnfree by default, it can be disabled later */
+ if ((dp->cdr_flags & CDR_BURNFREE) != 0)
+ dp->cdr_dstat->ds_cdrflags |= RF_BURNFREE;
+
+ if (driveropts != NULL) {
+ char *p;
+
+ if (strcmp(driveropts, "help") == 0) {
+ mmc_opthelp(dp, 0);
+ }
+
+ p = hasdrvopt(driveropts, "varirec");
+ if (p != NULL && (dp->cdr_flags & CDR_VARIREC) != 0) {
+ dp->cdr_dstat->ds_cdrflags |= RF_VARIREC;
+ }
+
+ p = hasdrvopt(driveropts, "gigarec");
+ if (p != NULL && (dp->cdr_flags & CDR_GIGAREC) != 0) {
+ dp->cdr_dstat->ds_cdrflags |= RF_GIGAREC;
+ }
+
+ p = hasdrvopt(driveropts, "audiomaster");
+ if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_AUDIOMASTER) != 0) {
+ dp->cdr_dstat->ds_cdrflags |= RF_AUDIOMASTER;
+ dp->cdr_dstat->ds_cdrflags &= ~RF_BURNFREE;
+ }
+ p = hasdrvopt(driveropts, "forcespeed");
+ if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_FORCESPEED) != 0) {
+ dp->cdr_dstat->ds_cdrflags |= RF_FORCESPEED;
+ }
+ p = hasdrvopt(driveropts, "tattooinfo");
+ if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_DISKTATTOO) != 0) {
+ get_tattoo_yamaha(usalp, TRUE, 0, 0);
+ }
+ p = hasdrvopt(driveropts, "tattoofile");
+ if (p != NULL && (dp->cdr_flags & CDR_DISKTATTOO) != 0) {
+ FILE *f;
+
+ if ((f = fileopen(p, "rb")) == NULL)
+ comerr("Cannot open '%s'.\n", p);
+
+ if (do_tattoo_yamaha(usalp, f) < 0)
+ errmsgno(EX_BAD, "Cannot do DiskT@2.\n");
+ fclose(f);
+ }
+ p = hasdrvopt(driveropts, "singlesession");
+ if (p != NULL && (dp->cdr_flags & CDR_SINGLESESS) != 0) {
+ if (*p == '1') {
+ dp->cdr_dstat->ds_cdrflags |= RF_SINGLESESS;
+ } else if (*p == '0') {
+ dp->cdr_dstat->ds_cdrflags &= ~RF_SINGLESESS;
+ }
+ }
+ p = hasdrvopt(driveropts, "hidecdr");
+ if (p != NULL && (dp->cdr_flags & CDR_HIDE_CDR) != 0) {
+ if (*p == '1') {
+ dp->cdr_dstat->ds_cdrflags |= RF_HIDE_CDR;
+ } else if (*p == '0') {
+ dp->cdr_dstat->ds_cdrflags &= ~RF_HIDE_CDR;
+ }
+ }
+ p = hasdrvopt(driveropts, "speedread");
+ if (p != NULL && (dp->cdr_flags & CDR_SPEEDREAD) != 0) {
+ if (*p == '1') {
+ dp->cdr_dstat->ds_cdrflags |= RF_SPEEDREAD;
+ } else if (*p == '0') {
+ dp->cdr_dstat->ds_cdrflags &= ~RF_SPEEDREAD;
+ }
+ }
+ }
+
+ if ((ret = get_supported_cdrw_media_types(usalp)) < 0) {
+ dp->cdr_cdrw_support = CDR_CDRW_ALL;
+ return (0);
+ }
+ dp->cdr_cdrw_support = ret;
+ if (lverbose > 1)
+ printf("Supported CD-RW media types: %02X\n", dp->cdr_cdrw_support);
+
+ return (0);
+}
+
+static int
+attach_mdvd(SCSI *usalp, cdr_t *dp)
+{
+ struct cd_mode_page_2A *mp;
+
+
+ allow_atapi(usalp, TRUE);/* Try to switch to 10 byte mode cmds */
+
+ usalp->silent++;
+ mp = mmc_cap(usalp, NULL);/* Get MMC capabilities in allocated mp */
+ usalp->silent--;
+ if (mp == NULL)
+ return (-1); /* Pre SCSI-3/mmc drive */
+
+ dp->cdr_cdcap = mp; /* Store MMC cap pointer */
+
+ dp->cdr_dstat->ds_dr_max_rspeed = a_to_u_2_byte(mp->max_read_speed)/1385;
+ if (dp->cdr_dstat->ds_dr_max_rspeed == 0)
+ dp->cdr_dstat->ds_dr_max_rspeed = 1385;
+ dp->cdr_dstat->ds_dr_cur_rspeed = a_to_u_2_byte(mp->cur_read_speed)/1385;
+ if (dp->cdr_dstat->ds_dr_cur_rspeed == 0)
+ dp->cdr_dstat->ds_dr_cur_rspeed = 1385;
+
+ dp->cdr_dstat->ds_dr_max_wspeed = a_to_u_2_byte(mp->max_write_speed)/1385;
+ if (mp->p_len >= 28)
+ dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->v3_cur_write_speed)/1385;
+ else
+ dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->cur_write_speed)/1385;
+
+ if (dp->cdr_speedmax > dp->cdr_dstat->ds_dr_max_wspeed)
+ dp->cdr_speedmax = dp->cdr_dstat->ds_dr_max_wspeed;
+
+ if (dp->cdr_speeddef > dp->cdr_speedmax)
+ dp->cdr_speeddef = dp->cdr_speedmax;
+
+
+ if (mp->loading_type == LT_TRAY)
+ dp->cdr_flags |= CDR_TRAYLOAD;
+ else if (mp->loading_type == LT_CADDY)
+ dp->cdr_flags |= CDR_CADDYLOAD;
+
+ if (mp->BUF != 0)
+ dp->cdr_flags |= CDR_BURNFREE;
+
+ check_writemodes_mdvd(usalp, dp);
+
+ if (driveropts != NULL) {
+ if (strcmp(driveropts, "help") == 0) {
+ mmc_opthelp(dp, 0);
+ }
+ }
+
+ return (0);
+}
+
+int
+check_writemodes_mmc(SCSI *usalp, cdr_t *dp)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ if (xdebug)
+ printf("Checking possible write modes: ");
+
+ /*
+ * Reset mp->test_write (-dummy) here.
+ */
+ deflt_writemodes_mmc(usalp, TRUE);
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ usalp->silent--;
+ return (-1);
+ }
+ if (len == 0) {
+ usalp->silent--;
+ return (-1);
+ }
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+
+ /*
+ * mp->test_write has already been reset in deflt_writemodes_mmc()
+ * Do not reset mp->test_write (-dummy) here. It should be set
+ * only at one place and only one time.
+ */
+
+ mp->write_type = WT_TAO;
+ mp->track_mode = TM_DATA;
+ mp->dbtype = DB_ROM_MODE1;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_TAO;
+ if (xdebug)
+ printf("TAO ");
+ } else
+ dp->cdr_flags &= ~CDR_TAO;
+
+ mp->write_type = WT_PACKET;
+ mp->track_mode |= TM_INCREMENTAL;
+/* mp->fp = (trackp->pktsize > 0) ? 1 : 0;*/
+/* i_to_4_byte(mp->packet_size, trackp->pktsize);*/
+ mp->fp = 0;
+ i_to_4_byte(mp->packet_size, 0);
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_PACKET;
+ if (xdebug)
+ printf("PACKET ");
+ } else
+ dp->cdr_flags &= ~CDR_PACKET;
+ mp->fp = 0;
+ i_to_4_byte(mp->packet_size, 0);
+ mp->track_mode = TM_DATA;
+ mp->write_type = WT_SAO;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_SAO;
+ if (xdebug)
+ printf("SAO ");
+ } else
+ dp->cdr_flags &= ~CDR_SAO;
+
+ if (dp->cdr_flags & CDR_SAO) {
+ mp->dbtype = DB_RAW_PQ;
+
+#ifdef __needed__
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_SRAW16;
+ if (xdebug)
+ printf("SAO/R16 ");
+ }
+#endif
+
+ mp->dbtype = DB_RAW_PW;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_SRAW96P;
+ if (xdebug)
+ printf("SAO/R96P ");
+ }
+
+ mp->dbtype = DB_RAW_PW_R;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_SRAW96R;
+ if (xdebug)
+ printf("SAO/R96R ");
+ }
+ }
+
+ mp->write_type = WT_RAW;
+ mp->dbtype = DB_RAW_PQ;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_RAW;
+ dp->cdr_flags |= CDR_RAW16;
+ if (xdebug)
+ printf("RAW/R16 ");
+ }
+
+ mp->dbtype = DB_RAW_PW;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_RAW;
+ dp->cdr_flags |= CDR_RAW96P;
+ if (xdebug)
+ printf("RAW/R96P ");
+ }
+
+ mp->dbtype = DB_RAW_PW_R;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_RAW;
+ dp->cdr_flags |= CDR_RAW96R;
+ if (xdebug)
+ printf("RAW/R96R ");
+ }
+
+ if (xdebug)
+ printf("\n");
+
+ /*
+ * Reset mp->test_write (-dummy) here.
+ */
+ deflt_writemodes_mmc(usalp, TRUE);
+ usalp->silent--;
+
+ return (0);
+}
+
+int
+check_writemodes_mdvd(SCSI *usalp, cdr_t *dp)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ if (xdebug)
+ printf("Checking possible write modes: ");
+
+ deflt_writemodes_mdvd(usalp, FALSE);
+
+ fillbytes((caddr_t)mode, sizeof(mode), '\0');
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x05, "DVD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ usalp->silent--;
+ return (-1);
+ }
+ if (len == 0) {
+ usalp->silent--;
+ return (-1);
+ }
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof(struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ mp->test_write = 0;
+
+ /*We only check for PACKET and SAO since these are the only supported modes for DVD */
+ /*XXX these checks are irrelevant because they are not medium sensitive. ie the device returns
+ error only when it does not support a given mode for ALL mediums. It should check using
+ GET CONFIGURATION command.*/
+
+ mp->write_type = WT_PACKET;
+ mp->fp = 0;
+ i_to_4_byte(mp->packet_size, 0);
+
+ if (set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_PACKET;
+ if (xdebug)
+ printf("PACKET ");
+ } else
+ dp->cdr_flags &= ~CDR_PACKET;
+ mp->fp = 0;
+ i_to_4_byte(mp->packet_size, 0);
+ mp->track_mode = TM_DATA;
+
+
+ mp->write_type = WT_SAO;
+
+ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ dp->cdr_flags |= CDR_SAO;
+ if (xdebug)
+ printf("SAO ");
+ } else
+ dp->cdr_flags &= ~CDR_SAO;
+
+
+ if (xdebug)
+ printf("\n");
+
+ deflt_writemodes_mdvd(usalp, TRUE);
+ usalp->silent--;
+ return (0);
+}
+
+static int
+deflt_writemodes_mmc(SCSI *usalp, BOOL reset_dummy)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ usalp->silent--;
+ return (-1);
+ }
+ if (len == 0) {
+ usalp->silent--;
+ return (-1);
+ }
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+ fprintf(stderr, "Audio pause len: %d\n", a_to_2_byte(mp->audio_pause_len));
+#endif
+
+ /*
+ * This is the only place where we reset mp->test_write (-dummy)
+ */
+ if (reset_dummy)
+ mp->test_write = 0;
+
+ /*
+ * Set default values:
+ * Write type = 01 (track at once)
+ * Track mode = 04 (CD-ROM)
+ * Data block type = 08 (CD-ROM)
+ * Session format = 00 (CD-ROM)
+ *
+ * XXX Note: the same code appears in check_writemodes_mmc() and
+ * XXX in speed_select_mmc().
+ */
+ mp->write_type = WT_TAO;
+ mp->track_mode = TM_DATA;
+ mp->dbtype = DB_ROM_MODE1;
+ mp->session_format = SES_DA_ROM; /* Matsushita has illegal def. value */
+
+ i_to_2_byte(mp->audio_pause_len, 150); /* LG has illegal def. value */
+
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+
+ mp->write_type = WT_SAO;
+ mp->LS_V = 0;
+ mp->copy = 0;
+ mp->fp = 0;
+ mp->multi_session = MS_NONE;
+ mp->host_appl_code = 0;
+
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) {
+ usalp->silent--;
+ return (-1);
+ }
+ }
+ usalp->silent--;
+ return (0);
+}
+
+static int
+deflt_writemodes_mdvd(SCSI *usalp, BOOL reset_dummy)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ fillbytes((caddr_t)mode, sizeof(mode), '\0');
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x05, "DVD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ usalp->silent--;
+ return (-1);
+ }
+ if (len == 0) {
+ usalp->silent--;
+ return (-1);
+ }
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof(struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ mp->test_write = 0;
+ /*
+ * This is the only place where we reset mp->test_write (-dummy) for DVD
+ */
+ if (reset_dummy)
+ mp->test_write = 0;
+
+ /*
+ * Set default values:
+ * Write type = 02 (session at once)
+ *
+ * XXX Note: the same code appears in check_writemodes_mmc() and
+ * XXX in speed_select_mmc().
+ */
+ mp->write_type = WT_SAO;
+ mp->track_mode = TM_DATA;
+ mp->dbtype = DB_ROM_MODE1;
+ mp->session_format = SES_DA_ROM;
+
+
+ if (set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+ return (0);
+}
+
+#ifdef PRINT_ATIP
+static void print_di(struct disk_info *dip);
+static void atip_printspeed(char *fmt, int speedindex, char speedtab[]);
+static void print_atip(SCSI *usalp, struct atipinfo *atp);
+#endif /* PRINT_ATIP */
+
+static int
+get_diskinfo(SCSI *usalp, struct disk_info *dip)
+{
+ int len;
+ int ret;
+
+ fillbytes((caddr_t)dip, sizeof (*dip), '\0');
+
+ /*
+ * Used to be 2 instead of 4 (now). But some Y2k ATAPI drives as used
+ * by IOMEGA create a DMA overrun if we try to transfer only 2 bytes.
+ */
+/* if (read_disk_info(usalp, (caddr_t)dip, 2) < 0)*/
+ if (read_disk_info(usalp, (caddr_t)dip, 4) < 0)
+ return (-1);
+ len = a_to_u_2_byte(dip->data_len);
+ len += 2;
+ ret = read_disk_info(usalp, (caddr_t)dip, len);
+
+#ifdef DEBUG
+ usal_prbytes("Disk info:", (Uchar *)dip,
+ len-usal_getresid(usalp));
+#endif
+ return (ret);
+}
+
+static void
+di_to_dstat(struct disk_info *dip, dstat_t *dsp)
+{
+ dsp->ds_diskid = a_to_u_4_byte(dip->disk_id);
+ if (dip->did_v)
+ dsp->ds_flags |= DSF_DID_V;
+ dsp->ds_disktype = dip->disk_type;
+ dsp->ds_diskstat = dip->disk_status;
+ dsp->ds_sessstat = dip->sess_status;
+ if (dip->erasable)
+ dsp->ds_flags |= DSF_ERA;
+
+ dsp->ds_trfirst = dip->first_track;
+ dsp->ds_trlast = dip->last_track_ls;
+ dsp->ds_trfirst_ls = dip->first_track_ls;
+
+ dsp->ds_maxblocks = msf_to_lba(dip->last_lead_out[1],
+ dip->last_lead_out[2],
+ dip->last_lead_out[3], TRUE);
+ /*
+ * Check for 0xFF:0xFF/0xFF which is an indicator for a complete disk
+ */
+ if (dsp->ds_maxblocks == 1166730)
+ dsp->ds_maxblocks = -1L;
+
+ dsp->ds_first_leadin = msf_to_lba(dip->last_lead_in[1],
+ dip->last_lead_in[2],
+ dip->last_lead_in[3], FALSE);
+ if (dsp->ds_first_leadin > 0)
+ dsp->ds_first_leadin = 0;
+
+ if (dsp->ds_last_leadout == 0 && dsp->ds_maxblocks >= 0)
+ dsp->ds_last_leadout = dsp->ds_maxblocks;
+ dsp->ds_trfirst=dip->first_track;
+ dsp->ds_trlast=dip->last_track_ls;
+ dsp->ds_trfirst_ls=dip->first_track_ls;
+}
+
+static int
+get_atip(SCSI *usalp, struct atipinfo *atp)
+{
+ int len;
+ int ret;
+
+ fillbytes((caddr_t)atp, sizeof (*atp), '\0');
+
+ /*
+ * Used to be 2 instead of sizeof (struct tocheader), but all
+ * other places in the code use sizeof (struct tocheader) too and
+ * some Y2k ATAPI drives as used by IOMEGA create a DMA overrun if we
+ * try to transfer only 2 bytes.
+ */
+ if (read_toc(usalp, (caddr_t)atp, 0, sizeof (struct tocheader), 0, FMT_ATIP) < 0)
+ return (-1);
+ len = a_to_u_2_byte(atp->hd.len);
+ len += 2;
+ ret = read_toc(usalp, (caddr_t)atp, 0, len, 0, FMT_ATIP);
+
+#ifdef DEBUG
+ usal_prbytes("ATIP info:", (Uchar *)atp,
+ len-usal_getresid(usalp));
+#endif
+ /*
+ * Yamaha sometimes returns zeroed ATIP info for disks without ATIP
+ */
+ if (atp->desc.lead_in[1] == 0 &&
+ atp->desc.lead_in[2] == 0 &&
+ atp->desc.lead_in[3] == 0 &&
+ atp->desc.lead_out[1] == 0 &&
+ atp->desc.lead_out[2] == 0 &&
+ atp->desc.lead_out[3] == 0)
+ return (-1);
+
+ if (atp->desc.lead_in[1] >= 0x90 && debug) {
+ /*
+ * Only makes sense with buggy Ricoh firmware.
+ */
+ errmsgno(EX_BAD, "Converting ATIP from BCD\n");
+ atp->desc.lead_in[1] = from_bcd(atp->desc.lead_in[1]);
+ atp->desc.lead_in[2] = from_bcd(atp->desc.lead_in[2]);
+ atp->desc.lead_in[3] = from_bcd(atp->desc.lead_in[3]);
+
+ atp->desc.lead_out[1] = from_bcd(atp->desc.lead_out[1]);
+ atp->desc.lead_out[2] = from_bcd(atp->desc.lead_out[2]);
+ atp->desc.lead_out[3] = from_bcd(atp->desc.lead_out[3]);
+ }
+
+ return (ret);
+}
+
+#ifdef PRINT_ATIP
+
+static int
+get_pma(SCSI *usalp)
+{
+ int len;
+ int ret;
+ char atp[1024];
+
+ fillbytes((caddr_t)atp, sizeof (*atp), '\0');
+
+ /*
+ * Used to be 2 instead of sizeof (struct tocheader), but all
+ * other places in the code use sizeof (struct tocheader) too and
+ * some Y2k ATAPI drives as used by IOMEGA create a DMA overrun if we
+ * try to transfer only 2 bytes.
+ */
+/* if (read_toc(usalp, (caddr_t)atp, 0, 2, 1, FMT_PMA) < 0)*/
+/* if (read_toc(usalp, (caddr_t)atp, 0, 2, 0, FMT_PMA) < 0)*/
+ if (read_toc(usalp, (caddr_t)atp, 0, sizeof (struct tocheader), 0, FMT_PMA) < 0)
+ return (-1);
+/* len = a_to_u_2_byte(atp->hd.len);*/
+ len = a_to_u_2_byte(atp);
+ len += 2;
+/* ret = read_toc(usalp, (caddr_t)atp, 0, len, 1, FMT_PMA);*/
+ ret = read_toc(usalp, (caddr_t)atp, 0, len, 0, FMT_PMA);
+
+#ifdef DEBUG
+ usal_prbytes("PMA:", (Uchar *)atp,
+ len-usal_getresid(usalp));
+#endif
+ ret = read_toc(usalp, (caddr_t)atp, 0, len, 1, FMT_PMA);
+
+#ifdef DEBUG
+ usal_prbytes("PMA:", (Uchar *)atp,
+ len-usal_getresid(usalp));
+#endif
+ return (ret);
+}
+
+#endif /* PRINT_ATIP */
+
+static int
+init_mmc(SCSI *usalp, cdr_t *dp)
+{
+ return (speed_select_mmc(usalp, dp, NULL));
+}
+
+static int
+getdisktype_mdvd(SCSI *usalp, cdr_t *dp)
+{
+ int ret = 0;
+ dstat_t *dsp = dp->cdr_dstat;
+
+ struct track_info track_info;
+ if(lverbose)
+ printf("HINT: use dvd+rw-mediainfo from dvd+rw-tools for information extraction.\n");
+ /* if(getdisktype_mmc(usalp, dp)<0)
+ return -1;
+ */
+
+ /* read rzone info to get the space left on disk */
+ /*ds_trlast is the last rzone on disk, can be invisible */
+ if(read_rzone_info(usalp, (caddr_t)&track_info, sizeof(track_info))>=0)
+ dsp->ds_maxblocks=a_to_u_4_byte(track_info.free_blocks)+a_to_4_byte(track_info.next_writable_addr);
+
+ dsp->ds_disktype&= ~DT_CD;
+ dsp->ds_disktype|= DT_DVD;
+
+ return (ret);
+
+}
+
+static int
+getdisktype_mmc(SCSI *usalp, cdr_t *dp)
+{
+extern char *buf;
+ dstat_t *dsp = dp->cdr_dstat;
+ struct disk_info *dip;
+ Uchar mode[0x100];
+ msf_t msf;
+ BOOL did_atip = FALSE;
+ BOOL did_dummy = FALSE;
+ int rplus;
+
+ msf.msf_min = msf.msf_sec = msf.msf_frame = 0;
+
+ /*
+ * It seems that there are drives that do not support to
+ * read ATIP (e.g. HP 7100)
+ * Also if a NON CD-R media is inserted, this will never work.
+ * For this reason, make a failure non-fatal.
+ */
+ usalp->silent++;
+ if (get_atip(usalp, (struct atipinfo *)mode) >= 0) {
+ struct atipinfo *atp = (struct atipinfo *)mode;
+
+ msf.msf_min = mode[8];
+ msf.msf_sec = mode[9];
+ msf.msf_frame = mode[10];
+ if (atp->desc.erasable) {
+ dsp->ds_flags |= DSF_ERA;
+ if (atp->desc.sub_type == 1)
+ dsp->ds_flags |= DSF_HIGHSP_ERA;
+ else if (atp->desc.sub_type == 2)
+ dsp->ds_flags |= DSF_ULTRASP_ERA;
+ else if (atp->desc.sub_type == 3)
+ dsp->ds_flags |= DSF_ULTRASP_ERA | DSF_ULTRASPP_ERA;
+ }
+ if (atp->desc.a1_v) {
+ if (atp->desc.clv_low != 0)
+ dsp->ds_at_min_speed = clv_to_speed[atp->desc.clv_low];
+ if (atp->desc.clv_high != 0)
+ dsp->ds_at_max_speed = clv_to_speed[atp->desc.clv_high];
+
+ if (atp->desc.erasable && atp->desc.sub_type == 1) {
+ if (atp->desc.clv_high != 0)
+ dsp->ds_at_max_speed = hs_clv_to_speed[atp->desc.clv_high];
+ }
+ }
+ if (atp->desc.a2_v && atp->desc.erasable && (atp->desc.sub_type == 2 || atp->desc.sub_type == 3)) {
+ Uint vlow;
+ Uint vhigh;
+
+ vlow = (atp->desc.a2[0] >> 4) & 0x07;
+ vhigh = atp->desc.a2[0] & 0x0F;
+ if (vlow != 0)
+ dsp->ds_at_min_speed = us_clv_to_speed[vlow];
+ if (vhigh != 0)
+ dsp->ds_at_max_speed = us_clv_to_speed[vhigh];
+ }
+ did_atip = TRUE;
+ }
+ usalp->silent--;
+
+#ifdef PRINT_ATIP
+ if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0 && did_atip) {
+ print_atip(usalp, (struct atipinfo *)mode);
+ pr_manufacturer(&msf,
+ ((struct atipinfo *)mode)->desc.erasable,
+ ((struct atipinfo *)mode)->desc.uru);
+ }
+#endif
+again:
+ dip = (struct disk_info *)buf;
+ if (get_diskinfo(usalp, dip) < 0)
+ return (-1);
+
+ /*
+ * Check for non writable disk first.
+ */
+
+ /* DVD+RW does not need to be blanked */
+ rplus = dsp->ds_cdrflags;
+ if (dp->profile == 0x1A) rplus = RF_BLANK;
+
+ if (dip->disk_status == DS_COMPLETE &&
+ (rplus & dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == RF_WRITE) {
+ if (!did_dummy) {
+ int xspeed = 0xFFFF;
+ int oflags = dp->cdr_cmdflags;
+
+ /*
+ * Try to clear the dummy bit to reset the virtual
+ * drive status. Not all drives support it even though
+ * it is mentioned in the MMC standard.
+ */
+ if (lverbose)
+ printf("Trying to clear drive status.\n");
+
+ dp->cdr_cmdflags &= ~F_DUMMY;
+ speed_select_mmc(usalp, dp, &xspeed);
+ dp->cdr_cmdflags = oflags;
+ did_dummy = TRUE;
+ goto again;
+ }
+ /*
+ * Trying to clear drive status did not work...
+ */
+ reload_media(usalp, dp);
+ }
+ if (get_diskinfo(usalp, dip) < 0)
+ return (-1);
+ di_to_dstat(dip, dsp);
+ if (!did_atip && dsp->ds_first_leadin < 0)
+ lba_to_msf(dsp->ds_first_leadin, &msf);
+
+ if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0 && !did_atip) {
+ print_min_atip(dsp->ds_first_leadin, dsp->ds_last_leadout);
+ if (dsp->ds_first_leadin < 0)
+ pr_manufacturer(&msf,
+ dip->erasable,
+ dip->uru);
+ }
+ dsp->ds_maxrblocks = disk_rcap(&msf, dsp->ds_maxblocks,
+ dip->erasable,
+ dip->uru);
+
+
+#ifdef PRINT_ATIP
+#ifdef DEBUG
+ if (get_atip(usalp, (struct atipinfo *)mode) < 0)
+ return (-1);
+ /*
+ * Get pma gibt Ärger mit CW-7502
+ * Wenn Die Disk leer ist, dann stuerzt alles ab.
+ * Firmware 4.02 kann nicht get_pma
+ */
+ if (dip->disk_status != DS_EMPTY) {
+/* get_pma();*/
+ }
+ printf("ATIP lead in: %ld (%02d:%02d/%02d)\n",
+ msf_to_lba(mode[8], mode[9], mode[10], FALSE),
+ mode[8], mode[9], mode[10]);
+ printf("ATIP lead out: %ld (%02d:%02d/%02d)\n",
+ msf_to_lba(mode[12], mode[13], mode[14], TRUE),
+ mode[12], mode[13], mode[14]);
+ print_di(dip);
+ print_atip(usalp, (struct atipinfo *)mode);
+#endif
+#endif /* PRINT_ATIP */
+ return (drive_getdisktype(usalp, dp));
+}
+
+#ifdef PRINT_ATIP
+
+#define DOES(what, flag) printf(" Does %s%s\n", flag?"":"not ", what);
+#define IS(what, flag) printf(" Is %s%s\n", flag?"":"not ", what);
+#define VAL(what, val) printf(" %s: %d\n", what, val[0]*256 + val[1]);
+#define SVAL(what, val) printf(" %s: %s\n", what, val);
+
+static void
+print_di(struct disk_info *dip)
+{
+ static char *ds_name[] = { "empty", "incomplete/appendable", "complete", "illegal" };
+ static char *ss_name[] = { "empty", "incomplete/appendable", "illegal", "complete", };
+
+ IS("erasable", dip->erasable);
+ printf("disk status: %s\n", ds_name[dip->disk_status]);
+ printf("session status: %s\n", ss_name[dip->sess_status]);
+ printf("first track: %d number of sessions: %d first track in last sess: %d last track in last sess: %d\n",
+ dip->first_track,
+ dip->numsess,
+ dip->first_track_ls,
+ dip->last_track_ls);
+ IS("unrestricted", dip->uru);
+ printf("Disk type: ");
+ switch (dip->disk_type) {
+
+ case SES_DA_ROM: printf("CD-DA or CD-ROM"); break;
+ case SES_CDI: printf("CDI"); break;
+ case SES_XA: printf("CD-ROM XA"); break;
+ case SES_UNDEF: printf("undefined"); break;
+ default: printf("reserved"); break;
+ }
+ printf("\n");
+ if (dip->did_v)
+ printf("Disk id: 0x%lX\n", a_to_u_4_byte(dip->disk_id));
+
+ printf("last start of lead in: %ld\n",
+ msf_to_lba(dip->last_lead_in[1],
+ dip->last_lead_in[2],
+ dip->last_lead_in[3], FALSE));
+ printf("last start of lead out: %ld\n",
+ msf_to_lba(dip->last_lead_out[1],
+ dip->last_lead_out[2],
+ dip->last_lead_out[3], TRUE));
+
+ if (dip->dbc_v)
+ printf("Disk bar code: 0x%lX%lX\n",
+ a_to_u_4_byte(dip->disk_barcode),
+ a_to_u_4_byte(&dip->disk_barcode[4]));
+
+ if (dip->num_opc_entries > 0) {
+ printf("OPC table:\n");
+ }
+}
+
+char *cdr_subtypes[] = {
+ "Normal Rewritable (CLV) media",
+ "High speed Rewritable (CAV) media",
+ "Medium Type A, low Beta category (A-)",
+ "Medium Type A, high Beta category (A+)",
+ "Medium Type B, low Beta category (B-)",
+ "Medium Type B, high Beta category (B+)",
+ "Medium Type C, low Beta category (C-)",
+ "Medium Type C, high Beta category (C+)",
+};
+
+char *cdrw_subtypes[] = {
+ "Normal Rewritable (CLV) media",
+ "High speed Rewritable (CAV) media",
+ "Ultra High speed Rewritable media",
+ "Ultra High speed+ Rewritable media",
+ "Medium Type B, low Beta category (B-)",
+ "Medium Type B, high Beta category (B+)",
+ "Medium Type C, low Beta category (C-)",
+ "Medium Type C, high Beta category (C+)",
+};
+
+static void
+atip_printspeed(char *fmt, int speedindex, char speedtab[])
+{
+ printf("%s:", fmt);
+ if (speedtab[speedindex] == 0) {
+ printf(" %2d (reserved val %2d)",
+ speedtab[speedindex], speedindex);
+ } else {
+ printf(" %2d", speedtab[speedindex]);
+ }
+}
+
+static void
+print_atip(SCSI *usalp, struct atipinfo *atp)
+{
+ char *sub_type;
+ char *speedvtab = clv_to_speed;
+
+ if (usalp->verbose)
+ usal_prbytes("ATIP info: ", (Uchar *)atp, sizeof (*atp));
+
+ printf("ATIP info from disk:\n");
+ printf(" Indicated writing power: %d\n", atp->desc.ind_wr_power);
+ if (atp->desc.erasable || atp->desc.ref_speed)
+ printf(" Reference speed: %d\n", clv_to_speed[atp->desc.ref_speed]);
+ IS("unrestricted", atp->desc.uru);
+/* printf(" Disk application code: %d\n", atp->desc.res5_05);*/
+ IS("erasable", atp->desc.erasable);
+ if (atp->desc.erasable)
+ sub_type = cdrw_subtypes[atp->desc.sub_type];
+ else
+ sub_type = cdr_subtypes[atp->desc.sub_type];
+ if (atp->desc.sub_type)
+ printf(" Disk sub type: %s (%d)\n", sub_type, atp->desc.sub_type);
+ printf(" ATIP start of lead in: %ld (%02d:%02d/%02d)\n",
+ msf_to_lba(atp->desc.lead_in[1],
+ atp->desc.lead_in[2],
+ atp->desc.lead_in[3], FALSE),
+ atp->desc.lead_in[1],
+ atp->desc.lead_in[2],
+ atp->desc.lead_in[3]);
+ printf(" ATIP start of lead out: %ld (%02d:%02d/%02d)\n",
+ msf_to_lba(atp->desc.lead_out[1],
+ atp->desc.lead_out[2],
+ atp->desc.lead_out[3], TRUE),
+ atp->desc.lead_out[1],
+ atp->desc.lead_out[2],
+ atp->desc.lead_out[3]);
+ if (atp->desc.a1_v) {
+ if (atp->desc.erasable && atp->desc.sub_type == 1) {
+ speedvtab = hs_clv_to_speed;
+ }
+ if (atp->desc.a2_v && (atp->desc.sub_type == 2 || atp->desc.sub_type == 3)) {
+ speedvtab = us_clv_to_speed;
+ }
+ if (atp->desc.clv_low != 0 || atp->desc.clv_high != 0) {
+ atip_printspeed(" 1T speed low",
+ atp->desc.clv_low, speedvtab);
+ atip_printspeed(" 1T speed high",
+ atp->desc.clv_high, speedvtab);
+ printf("\n");
+ }
+ }
+ if (atp->desc.a2_v) {
+ Uint vlow;
+ Uint vhigh;
+
+ vlow = (atp->desc.a2[0] >> 4) & 0x07;
+ vhigh = atp->desc.a2[0] & 0x0F;
+
+ if (vlow != 0 || vhigh != 0) {
+ atip_printspeed(" 2T speed low",
+ vlow, speedvtab);
+ atip_printspeed(" 2T speed high",
+ vhigh, speedvtab);
+ printf("\n");
+ }
+ }
+ if (atp->desc.a1_v) {
+ printf(" power mult factor: %d %d\n", atp->desc.power_mult, atp->desc.tgt_y_pow);
+ if (atp->desc.erasable)
+ printf(" recommended erase/write power: %d\n", atp->desc.rerase_pwr_ratio);
+ }
+ if (atp->desc.a1_v) {
+ printf(" A1 values: %02X %02X %02X\n",
+ (&atp->desc.res15)[1],
+ (&atp->desc.res15)[2],
+ (&atp->desc.res15)[3]);
+ }
+ if (atp->desc.a2_v) {
+ printf(" A2 values: %02X %02X %02X\n",
+ atp->desc.a2[0],
+ atp->desc.a2[1],
+ atp->desc.a2[2]);
+ }
+ if (atp->desc.a3_v) {
+ printf(" A3 values: %02X %02X %02X\n",
+ atp->desc.a3[0],
+ atp->desc.a3[1],
+ atp->desc.a3[2]);
+ }
+}
+#endif /* PRINT_ATIP */
+
+static int
+speed_select_mmc(SCSI *usalp, cdr_t *dp, int *speedp)
+{
+ Uchar mode[0x100];
+ Uchar moder[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+ struct ricoh_mode_page_30 *rp = NULL;
+ int val;
+ BOOL forcespeed = FALSE;
+ BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;
+
+ if (speedp)
+ curspeed = *speedp;
+
+ /*
+ * Do not reset mp->test_write (-dummy) here.
+ */
+ deflt_writemodes_mmc(usalp, FALSE);
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+
+ if(dummy) {
+ mp->test_write = 1;
+ /* but it does not work on DVD+RW and -RAM, also bail out on other
+ * types that have not been tested yet */
+ int profile=get_curprofile(usalp);
+ switch(profile) {
+ case(0x12):
+ case(0x1a):
+ case(0x2a):
+ case(0x43):
+ case(0x52):
+ {
+ fprintf(stderr,
+ "Dummy mode not possible with %s.\n",
+ mmc_obtain_profile_name(profile) );
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ else
+ mp->test_write = 0;
+
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1))
+ return (-1);
+
+ /*
+ * Neither set nor get speed.
+ */
+ if (speedp == 0)
+ return (0);
+
+
+ rp = get_justlink_ricoh(usalp, moder);
+ if (mmc_isyamaha(usalp)) {
+ forcespeed = FALSE;
+ } else if (mmc_isplextor(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) {
+ int pwr;
+
+ pwr = check_powerrec_plextor(usalp);
+ if (pwr >= 0)
+ forcespeed = (pwr == 0);
+ } else if ((dp->cdr_flags & CDR_FORCESPEED) != 0) {
+ forcespeed = rp && rp->AWSCD != 0;
+ }
+
+ if (lverbose && (dp->cdr_flags & CDR_FORCESPEED) != 0)
+ printf("Forcespeed is %s.\n", forcespeed?"ON":"OFF");
+
+ if (!forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) != 0) {
+ printf("Turning forcespeed on\n");
+ forcespeed = TRUE;
+ }
+ if (forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) == 0) {
+ printf("Turning forcespeed off\n");
+ forcespeed = FALSE;
+ }
+ if (mmc_isplextor(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) {
+ powerrec_plextor(usalp, !forcespeed);
+ }
+ if (!mmc_isyamaha(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) {
+
+ if (rp) {
+ rp->AWSCD = forcespeed?1:0;
+ set_mode_params(usalp, "Ricoh Vendor Page", moder, moder[0]+1, 0, -1);
+ rp = get_justlink_ricoh(usalp, moder);
+ }
+ }
+
+ /*
+ * 44100 * 2 * 2 = 176400 bytes/s
+ *
+ * The right formula would be:
+ * tmp = (((long)curspeed) * 1764) / 10;
+ *
+ * But the standard is rounding the wrong way.
+ * Furtunately rounding down is guaranteed.
+ */
+ val = curspeed*177;
+ if (val > 0xFFFF)
+ val = 0xFFFF;
+ if (mmc_isyamaha(usalp) && forcespeed) {
+ if (force_speed_yamaha(usalp, -1, val) < 0)
+ return (-1);
+ } else if (mmc_set_speed(usalp, -1, val, ROTCTL_CLV) < 0) {
+ return (-1);
+ }
+
+ if (scsi_get_speed(usalp, 0, &val) >= 0) {
+ if (val > 0) {
+ fprintf(stderr, "Speed set to %d KB/s\n", val);
+ curspeed = val / 176;
+ *speedp = curspeed;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Some drives do not round up when writespeed is e.g. 1 and
+ * the minimum write speed of the drive is higher. Try to increment
+ * the write speed unti it gets accepted by the drive.
+ */
+static int
+mmc_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl)
+{
+ int rs;
+ int ws;
+ int ret = -1;
+ int c;
+ int k;
+
+ if (scsi_get_speed(usalp, &rs, &ws) >= 0) {
+ if (readspeed < 0)
+ readspeed = rs;
+ if (writespeed < 0)
+ writespeed = ws;
+ }
+ if (writespeed < 0 || writespeed > 0xFFFF)
+ return (ret);
+
+ usalp->silent++;
+ while (writespeed <= 0xFFFF) {
+ ret = scsi_set_speed(usalp, readspeed, writespeed, rotctl);
+ if (ret >= 0)
+ break;
+ c = usal_sense_code(usalp);
+ k = usal_sense_key(usalp);
+ /*
+ * Abort quickly if it does not make sense to repeat.
+ * 0x24 == Invalid field in cdb
+ * 0x24 means illegal speed.
+ */
+ if ((k != SC_ILLEGAL_REQUEST) || (c != 0x24)) {
+ if (usalp->silent <= 1)
+ usal_printerr(usalp);
+ usalp->silent--;
+ return (-1);
+ }
+ writespeed += 177;
+ }
+ if (ret < 0 && usalp->silent <= 1)
+ usal_printerr(usalp);
+ usalp->silent--;
+
+ return (ret);
+}
+
+static int
+speed_select_mdvd(SCSI *usalp, cdr_t *dp, int *speedp)
+{
+ int retcode;
+ char perf_desc[28];
+ int write_speed = *speedp * 1385;
+
+ /* For the moment we just divide the CD speed by 7*/
+
+ if(speedp!=NULL)
+ (*speedp)=(*speedp)*8;
+
+ memset(perf_desc, 0, sizeof(perf_desc));
+
+ /* Write Rotation Control = ROTCTL_CLV
+ * | Restore Logical Unit Defaults = 0
+ * | Exact = 0
+ * | Random Access = 0)
+ */
+ perf_desc[0]= ROTCTL_CLV << 3 | 0 << 2 | 0 << 1 | 0;
+ /* Start LBA to 0 */
+ perf_desc[4] = 0;
+ perf_desc[5] = 0;
+ perf_desc[6] = 0;
+ perf_desc[7] = 0;
+ /* End LBA set to 0 (setting to 0xffffffff failed on my LG burner
+ */
+ perf_desc[8] = 0;
+ perf_desc[9] = 0;
+ perf_desc[10] = 0;
+ perf_desc[11] = 0;
+ /* Read Speed = 0xFFFF */
+ perf_desc[12] = 0;
+ perf_desc[13] = 0;
+ perf_desc[14] = 0xFF;
+ perf_desc[15] = 0xFF;
+ /* Read Time = 1s */
+ perf_desc[18] = 1000 >> 8;
+ perf_desc[19] = 1000 & 0xFF;
+ /* Write Speed */
+ perf_desc[20] = write_speed >> 24;
+ perf_desc[21] = write_speed >> 16 & 0xFF;
+ perf_desc[22] = write_speed >> 8 & 0xFF;
+ perf_desc[23] = write_speed & 0xFF;
+ /* Write Time = 1s */
+ perf_desc[26] = 1000 >> 8;
+ perf_desc[27] = 1000 & 0xFF;
+
+ /* retcode = scsi_set_streaming(usalp, NULL, 0); */
+ retcode = scsi_set_streaming(usalp, perf_desc, sizeof(perf_desc));
+ if (retcode == -1) return retcode;
+ retcode = speed_select_mmc(usalp, dp, speedp);
+ if(speedp!=NULL)
+ (*speedp)=(*speedp)/7;
+ return retcode;
+}
+
+static int
+next_wr_addr_mmc(SCSI *usalp, track_t *trackp, long *ap)
+{
+ struct track_info track_info;
+ long next_addr;
+ int result = -1;
+
+
+ /*
+ * Reading info for current track may require doing the read_track_info
+ * with either the track number (if the track is currently being written)
+ * or with 0xFF (if the track hasn't been started yet and is invisible
+ */
+
+ if (trackp != 0 && trackp->track > 0 && is_packet(trackp)) {
+ usalp->silent++;
+ result = read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_TRACK,
+ trackp->trackno,
+ sizeof (track_info));
+ usalp->silent--;
+ }
+
+ if (result < 0) {
+ if (read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_TRACK, 0xFF,
+ sizeof (track_info)) < 0) {
+ errmsgno(EX_BAD, "Cannot get next writable address for 'invisible' track.\n");
+ errmsgno(EX_BAD, "This means that we are checking recorded media.\n");
+ errmsgno(EX_BAD, "This media cannot be written in streaming mode anymore.\n");
+ errmsgno(EX_BAD, "If you like to write to 'preformatted' RW media, try to blank the media first.\n");
+ return (-1);
+ }
+ }
+ if (usalp->verbose)
+ usal_prbytes("track info:", (Uchar *)&track_info,
+ sizeof (track_info)-usal_getresid(usalp));
+ next_addr = a_to_4_byte(track_info.next_writable_addr);
+ if (ap)
+ *ap = next_addr;
+ return (0);
+}
+
+static int
+write_leadin_mmc(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 ((*dp->cdr_send_cue)(usalp, dp, trackp) < 0) {
+ errmsgno(EX_BAD, "Cannot send CUE sheet.\n");
+ return (-1);
+ }
+
+ (*dp->cdr_next_wr_address)(usalp, &trackp[0], &startsec);
+ if (trackp[0].flags & TI_TEXT) {
+ startsec = dp->cdr_dstat->ds_first_leadin;
+ printf("SAO startsec: %ld\n", startsec);
+ } else if (startsec <= 0 && startsec != -150) {
+ if(lverbose>2)
+ fprintf(stderr, "WARNING: Drive returns wrong startsec (%ld) using -150\n",
+ startsec);
+ 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;
+ }
+#ifdef XXX
+ if (debug || lverbose)
+ printf("Writing lead-in...\n");
+
+ pad_track(usalp, dp, &trackp[1], -150, (Llong)0,
+ FALSE, 0);
+#endif
+ }
+/* if (flags & F_RAW) {*/
+ if (wm_base(dp->cdr_dstat->ds_wrmode) == WM_RAW) {
+ /*
+ * In RAW write mode, we now write the lead in (TOC).
+ */
+ (*dp->cdr_next_wr_address)(usalp, &trackp[0], &startsec);
+ if (startsec > -4500) {
+ /*
+ * There must be at least 1 minute lead-in.
+ */
+ errmsgno(EX_BAD, "WARNING: Drive returns wrong startsec (%ld) using %ld from ATIP\n",
+ startsec, (long)dp->cdr_dstat->ds_first_leadin);
+ startsec = dp->cdr_dstat->ds_first_leadin;
+ }
+ if (startsec > -4500) {
+ errmsgno(EX_BAD, "Illegal startsec (%ld)\n", startsec);
+ return (-1);
+ }
+ if (debug || lverbose)
+ printf("Writing lead-in at sector %ld\n", startsec);
+ if (write_leadin(usalp, dp, trackp, startsec) < 0)
+ return (-1);
+ dp->cdr_dstat->ds_cdrflags |= RF_LEADIN;
+ }
+ return (0);
+}
+
+int st2mode[] = {
+ 0, /* 0 */
+ TM_DATA, /* 1 ST_ROM_MODE1 */
+ TM_DATA, /* 2 ST_ROM_MODE2 */
+ 0, /* 3 */
+ 0, /* 4 ST_AUDIO_NOPRE */
+ TM_PREEM, /* 5 ST_AUDIO_PRE */
+ 0, /* 6 */
+ 0, /* 7 */
+};
+
+static int
+next_wr_addr_mdvd(SCSI *usalp, track_t *trackp, long *ap)
+{
+ int track=0;
+ struct track_info track_info;
+ long next_addr;
+ int result = -1;
+ struct disk_info disk_info;
+ if (trackp){
+ track = trackp->trackno;
+ }
+
+ if (trackp != 0 && track > 0 && is_packet(trackp)) {
+ usalp->silent++;
+ result = read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_SESS, track, sizeof(track_info));
+ usalp->silent--;
+ if (scsi_in_progress(usalp)){
+ return -1;
+ }
+
+ }
+
+ if (result < 0) {
+ /* Get the last rzone*/
+ if(read_disk_info(usalp,(caddr_t)&disk_info,8)<0)
+ return (-1);
+
+ /* if (read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_SESS, 0xFF, sizeof(track_info)) < 0) */
+ if (read_rzone_info(usalp, (caddr_t)&track_info, sizeof(track_info)) < 0)
+ return (-1);
+ }
+ if (usalp->verbose)
+ usal_prbytes("track info:", (Uchar *)&track_info,
+ sizeof(track_info)-usal_getresid(usalp));
+ next_addr = a_to_4_byte(track_info.next_writable_addr);
+ if (ap)
+ *ap = next_addr;
+ return (0);
+}
+
+static int
+open_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ 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);
+ }
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+
+/* mp->track_mode = ???;*/
+ mp->track_mode = st2mode[trackp->sectype & ST_MASK];
+/* mp->copy = ???;*/
+ mp->dbtype = trackp->dbtype;
+
+/*i_to_short(mp->audio_pause_len, 300);*/
+/*i_to_short(mp->audio_pause_len, 150);*/
+/*i_to_short(mp->audio_pause_len, 0);*/
+
+ if (is_packet(trackp)) {
+ mp->write_type = WT_PACKET;
+ mp->track_mode |= TM_INCREMENTAL;
+ mp->fp = (trackp->pktsize > 0) ? 1 : 0;
+ i_to_4_byte(mp->packet_size, trackp->pktsize);
+ } else if (is_tao(trackp)) {
+ mp->write_type = WT_TAO;
+ mp->fp = 0;
+ i_to_4_byte(mp->packet_size, 0);
+ } else {
+ errmsgno(EX_BAD, "Unknown write mode.\n");
+ return (-1);
+ }
+ if (trackp->isrc) {
+ mp->ISRC[0] = 0x80; /* Set ISRC valid */
+ strncpy((char *)&mp->ISRC[1], trackp->isrc, 12);
+
+ } else {
+ fillbytes(&mp->ISRC[0], sizeof (mp->ISRC), '\0');
+ }
+
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, trackp->secsize))
+ return (-1);
+
+ return (0);
+}
+
+static int
+open_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ if (is_packet(trackp)) {
+ fillbytes((caddr_t)mode, sizeof(mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "DVD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof(struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ mp->write_type = WT_PACKET;
+ mp->LS_V = 1;
+ /*For now we set the link size to 0x10(32k) because Pioneer-A03 only support this */
+ mp->link_size=0x10;
+ mp->fp = 1;
+ i_to_4_byte(mp->packet_size, trackp->pktsize);
+ } else {
+ return 0;
+ }
+
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, trackp->secsize))
+ return (-1);
+
+ return (0);
+}
+
+static int
+close_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ int ret;
+
+ if (!is_tao(trackp) && !is_packet(trackp))
+ return (0);
+
+ if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) {
+ printf("Trouble flushing the cache\n");
+ return (-1);
+ }
+ wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */
+ if (is_packet(trackp) && !is_noclose(trackp)) {
+ /* close the incomplete track */
+ ret = scsi_close_tr_session(usalp, CL_TYPE_TRACK, 0xFF,
+ (dp->cdr_cmdflags&F_IMMED) != 0);
+ wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */
+ return (ret);
+ }
+ return (0);
+}
+
+static int
+close_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ int ret;
+ if (!is_packet(trackp))
+ return (0);
+
+ if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) {
+ printf("Trouble flushing the cache\n");
+ return -1;
+ }
+ wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */
+ if (is_packet(trackp) && !is_noclose(trackp)) {
+ /* close the incomplete track */
+ ret = scsi_close_tr_session(usalp, 1, 0xFF, (dp->cdr_cmdflags&F_IMMED) != 0);
+ wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */
+ return (ret);
+ }
+ return (0);
+}
+
+int toc2sess[] = {
+ SES_DA_ROM, /* CD-DA */
+ SES_DA_ROM, /* CD-ROM */
+ SES_XA, /* CD-ROM XA mode 1 */
+ SES_XA, /* CD-ROM XA MODE 2 */
+ SES_CDI, /* CDI */
+ SES_DA_ROM, /* Invalid - use default */
+ SES_DA_ROM, /* Invalid - use default */
+};
+
+static int
+open_session_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ Uchar mode[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ mp->write_type = WT_TAO; /* fix to allow DAO later */
+ /*
+ * We need to set the right dbtype here because Sony drives
+ * don't like multi session in to be set with DB_ROM_MODE1
+ * which is set by us at the beginning as default as some drives
+ * have illegal default values.
+ */
+ mp->track_mode = st2mode[trackp[0].sectype & ST_MASK];
+ mp->dbtype = trackp[0].dbtype;
+
+ if (!is_tao(trackp) && !is_packet(trackp)) {
+ mp->write_type = WT_SAO;
+ if (dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER)
+ mp->write_type = 8;
+ mp->track_mode = 0;
+ mp->dbtype = DB_RAW;
+ }
+ if (is_raw(trackp)) {
+ mp->write_type = WT_RAW;
+ mp->track_mode = 0;
+
+ if (is_raw16(trackp)) {
+ mp->dbtype = DB_RAW_PQ;
+ } else if (is_raw96r(trackp)) {
+ mp->dbtype = DB_RAW_PW_R;
+ } else {
+ mp->dbtype = DB_RAW_PW;
+ }
+ }
+
+ mp->multi_session = (track_base(trackp)->tracktype & TOCF_MULTI) ?
+ MS_MULTI : MS_NONE;
+ mp->session_format = toc2sess[track_base(trackp)->tracktype & TOC_MASK];
+
+ if (trackp->isrc) {
+ mp->media_cat_number[0] = 0x80; /* Set MCN valid */
+ strncpy((char *)&mp->media_cat_number[1], trackp->isrc, 13);
+
+ } else {
+ fillbytes(&mp->media_cat_number[0], sizeof (mp->media_cat_number), '\0');
+ }
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1))
+ return (-1);
+
+ return (0);
+}
+
+static int
+open_session_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ Uchar mode[0x100];
+ int tracks = trackp->tracks;
+
+ int len;
+ struct cd_mode_page_05 *mp;
+ Ulong totalsize;
+ int i;
+ int profile;
+
+ fillbytes((caddr_t)mode, sizeof(mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "DVD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof(struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+ if(is_packet(trackp)){
+ mp->write_type=WT_PACKET;
+ mp->fp=0;
+ mp->BUFE=1;
+ mp->track_mode=1;
+ }else{
+ mp->write_type = WT_SAO;
+ }
+
+ mp->multi_session = (track_base(trackp)->tracktype & TOCF_MULTI) ?
+ MS_MULTI : MS_NONE;
+ mp->session_format = toc2sess[track_base(trackp)->tracktype & TOC_MASK];
+
+ /* Enable Burnfree by default, allow to disable. XXX Sucks, duplicated functionality. */
+ if (dp->cdr_cdcap->BUF != 0) {
+ if (lverbose > 2)
+ fprintf(stderr,
+ "BURN-Free is %s.\n"
+ "Turning BURN-Free on\n",
+ mp->BUFE?"ON":"OFF");
+ mp->BUFE = 1;
+ }
+ if (driveropts != NULL) {
+ if ((strcmp(driveropts, "noburnproof") == 0 ||
+ strcmp(driveropts, "noburnfree") == 0)) {
+ if(lverbose>1)
+ fprintf(stderr, "Turning BURN-Free off\n");
+ mp->BUFE = 0;
+ }
+ else if ((strcmp(driveropts, "burnproof") == 0 ||
+ strcmp(driveropts, "burnfree") == 0)) {
+ /* a NOP, we enable burnfree by default */
+ if(lverbose>2)
+ fprintf(stderr, "Found burnproof/burnfree in driveropts, those options are enabled by default now.");
+ }
+ else if (strcmp(driveropts, "help") == 0) {
+ mmc_opthelp(dp, 0);
+ }
+ else {
+ errmsgno(EX_BAD, "Bad driver opts '%s'.\n", driveropts);
+ mmc_opthelp(dp, EX_BAD);
+ }
+ }
+
+
+ if (!set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1))
+ return (-1);
+
+
+ totalsize=0;
+ for(i=1;i<=tracks;i++) {
+ totalsize+=trackp[i].tracksecs;
+ }
+
+ profile = get_curprofile(usalp);
+ if(!is_packet(trackp) && profile != 0x1A){
+ /* in DAO mode we need to reserve space for the track*/
+ if(reserve_track(usalp, totalsize)<0)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+waitfix_mmc(SCSI *usalp, int secs)
+{
+ char dibuf[16];
+ int i;
+ int key;
+#define W_SLEEP 2
+
+ usalp->silent++;
+ for (i = 0; i < secs/W_SLEEP; i++) {
+ if (read_disk_info(usalp, dibuf, sizeof (dibuf)) >= 0) {
+ usalp->silent--;
+ return (0);
+ }
+ key = usal_sense_key(usalp);
+ if (key != SC_UNIT_ATTENTION && key != SC_NOT_READY)
+ break;
+ sleep(W_SLEEP);
+ }
+ usalp->silent--;
+ return (-1);
+#undef W_SLEEP
+}
+
+static int
+fixate_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ int ret = 0;
+ int key = 0;
+ int code = 0;
+ struct timeval starttime;
+ struct timeval stoptime;
+ int dummy = (track_base(trackp)->tracktype & TOCF_DUMMY) != 0;
+
+ if(debug)
+ printf("fixate_mmc\n");
+ starttime.tv_sec = 0;
+ starttime.tv_usec = 0;
+ stoptime = starttime;
+ gettimeofday(&starttime, (struct timezone *)0);
+
+ if (dummy && lverbose)
+ printf("WARNING: Some drives don't like fixation in dummy mode.\n");
+
+ usalp->silent++;
+ if(debug)
+ printf("is_tao: %d,is_packet: %d\n", is_tao(trackp), is_packet(trackp));
+ if (is_tao(trackp) || is_packet(trackp)) {
+ ret = scsi_close_tr_session(usalp, CL_TYPE_SESSION, 0,
+ (dp->cdr_cmdflags&F_IMMED) != 0);
+ } else {
+ if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) {
+ if (!scsi_in_progress(usalp))
+ printf("Trouble flushing the cache\n");
+ }
+ }
+ usalp->silent--;
+ key = usal_sense_key(usalp);
+ code = usal_sense_code(usalp);
+
+ usalp->silent++;
+ if (debug && !unit_ready(usalp)) {
+ fprintf(stderr, "Early return from fixating. Ret: %d Key: %d, Code: %d\n", ret, key, code);
+ }
+ usalp->silent--;
+
+ if (ret >= 0) {
+ wait_unit_ready(usalp, 420/curspeed); /* XXX Wait for ATAPI */
+ waitfix_mmc(usalp, 420/curspeed); /* XXX Wait for ATAPI */
+ return (ret);
+ }
+
+ if ((dummy != 0 && (key != SC_ILLEGAL_REQUEST)) ||
+ /*
+ * Try to suppress messages from drives that don't like fixation
+ * in -dummy mode.
+ */
+ ((dummy == 0) &&
+ (((key != SC_UNIT_ATTENTION) && (key != SC_NOT_READY)) ||
+ ((code != 0x2E) && (code != 0x04))))) {
+ /*
+ * UNIT ATTENTION/2E seems to be a magic for old Mitsumi ATAPI drives
+ * NOT READY/ code 4 qual 7 (logical unit not ready, operation in progress)
+ * seems to be a magic for newer Mitsumi ATAPI drives
+ * NOT READY/ code 4 qual 8 (logical unit not ready, long write in progress)
+ * seems to be a magic for SONY drives
+ * when returning early from fixating.
+ * Try to supress the error message in this case to make
+ * simple minded users less confused.
+ */
+ usal_printerr(usalp);
+ usal_printresult(usalp); /* XXX restore key/code in future */
+ }
+
+ if (debug && !unit_ready(usalp)) {
+ fprintf(stderr, "Early return from fixating. Ret: %d Key: %d, Code: %d\n", ret, key, code);
+ }
+
+ wait_unit_ready(usalp, 420); /* XXX Wait for ATAPI */
+ waitfix_mmc(usalp, 420/curspeed); /* XXX Wait for ATAPI */
+
+ if (!dummy &&
+ (ret >= 0 || (key == SC_UNIT_ATTENTION && code == 0x2E))) {
+ /*
+ * Some ATAPI drives (e.g. Mitsumi) imply the
+ * IMMED bit in the SCSI cdb. As there seems to be no
+ * way to properly check for the real end of the
+ * fixating process we wait for the expected time.
+ */
+ gettimeofday(&stoptime, (struct timezone *)0);
+ timevaldiff(&starttime, &stoptime);
+ if (stoptime.tv_sec < (220 / curspeed)) {
+ unsigned secs;
+
+ if (lverbose) {
+ printf("Actual fixating time: %ld seconds\n",
+ (long)stoptime.tv_sec);
+ }
+ secs = (280 / curspeed) - stoptime.tv_sec;
+ if (lverbose) {
+ printf("ATAPI early return: sleeping %d seconds.\n",
+ secs);
+ }
+ sleep(secs);
+ }
+ }
+ return (ret);
+}
+
+static int
+fixate_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ int ret;
+ if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) {
+ printf("Trouble flushing the cache\n");
+ return -1;
+ }
+ wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */
+ /*set a really BIG timeout and call fixate_mmc
+ The BIG timeout is needed in case there was a very short rzone to write at the
+ beginning of the disk, because lead-out needs to be at some distance.
+ */
+ if(debug)
+ printf("fixate_mdvd\n");
+ usal_settimeout(usalp, 1000);
+ if(is_packet(trackp) || dp->profile == 0x1B){
+ scsi_close_tr_session(usalp, CL_TYPE_SESSION, 0, FALSE);
+ }
+ ret = fixate_mmc(usalp, dp, trackp);
+ if (dp->profile == 0x2B) {
+ scsi_close_tr_session(usalp, CL_TYPE_OPEN_SESSION, 0, FALSE);
+ scsi_close_tr_session(usalp, CL_TYPE_FINALISE_MINRAD, 0, FALSE);
+ }
+ usal_settimeout(usalp, 200);
+
+ return ret;
+}
+
+char *blank_types[] = {
+ "entire disk",
+ "PMA, TOC, pregap",
+ "incomplete track",
+ "reserved track",
+ "tail of track",
+ "closing of last session",
+ "last session",
+ "reserved blanking type",
+};
+
+char *format_types[] = {
+ "full format",
+ "background format",
+ "forced format",
+};
+
+static int
+blank_mmc(SCSI *usalp, cdr_t *dp, long addr, int blanktype)
+{
+ BOOL cdrr = FALSE; /* Read CD-R */
+ BOOL cdwr = FALSE; /* Write CD-R */
+ BOOL cdrrw = FALSE; /* Read CD-RW */
+ BOOL cdwrw = FALSE; /* Write CD-RW */
+ int ret;
+
+ mmc_check(usalp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL, NULL);
+ if (!cdwrw)
+ return (blank_dummy(usalp, dp, addr, blanktype));
+
+ if (dp->profile == 0x1A) {
+ printf("Error: this media does not support blanking, ignoring.\n");
+ return (blank_dummy(usalp, dp, addr, blanktype));
+ }
+ if (lverbose) {
+ printf("Blanking %s\n", blank_types[blanktype & 0x07]);
+ flush();
+ }
+
+ ret = scsi_blank(usalp, addr, blanktype, (dp->cdr_cmdflags&F_IMMED) != 0);
+ if (ret < 0)
+ return (ret);
+
+ wait_unit_ready(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */
+ waitfix_mmc(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */
+ return (ret);
+}
+
+static int format_mdvd(SCSI *usalp, cdr_t *dp, int formattype)
+{
+extern char *buf;
+ BOOL dvdwr = FALSE; /* Write DVD */
+ int ret;
+ int profile;
+ char addr[12];
+ struct disk_info *dip;
+
+ if (debug || lverbose > 2)
+ printf("format_mdvd\n");
+ mmc_check(usalp, NULL, NULL, NULL, NULL, NULL, &dvdwr);
+ if (!dvdwr)
+ return (format_dummy(usalp, dp, formattype));
+
+ if (debug || lverbose > 2)
+ printf("format_mdvd: drive is a dvd burner.\n");
+ profile = get_curprofile(usalp);
+ if (profile != 0x1A) {
+ printf("Error: only support DVD+RW formating, ignoring.\n");
+ return (format_dummy(usalp, dp, formattype));
+ }
+ dip = (struct disk_info *)buf;
+ if (get_diskinfo(usalp, dip) < 0)
+ return -1;
+
+ if (dip->disk_status & 3 && formattype != FORCE_FORMAT) {
+ printf("Error: disk already formated, ignoring.\n");
+ return -1;
+ }
+ addr[0] = 0; /* "Reserved" */
+ addr[1] = 2; /* "IMMED" flag */
+ addr[2] = 0; /* "Descriptor Length" (MSB) */
+ addr[3] = 8; /* "Descriptor Length" (LSB) */
+ addr[4+0] = 0xff;
+ addr[4+1] = 0xff;
+ addr[4+2] = 0xff;
+ addr[4+3] = 0xff;
+ addr[4+4] = 0x26<<2;
+ addr[4+5] = 0;
+ addr[4+6] = 0;
+ addr[4+7] = 0;
+ if (formattype == FORCE_FORMAT) {
+ printf("format_mdvd: forcing reformat.\n");
+ formattype = FULL_FORMAT;
+ addr[4+0] = 0;
+ addr[4+1] = 0;
+ addr[4+2] = 0;
+ addr[4+3] = 0;
+ addr[4+7] = 1;
+ } else {
+ printf("format_mdvd: media is unformated.\n");
+ }
+
+ if (lverbose) {
+ printf("Formating %s\n", format_types[formattype & 0x07]);
+ flush();
+ }
+ if (formattype == FULL_FORMAT) {
+ ret = scsi_format(usalp, (caddr_t)&addr, sizeof(addr), FALSE);
+ } else {
+ ret = scsi_format(usalp, (caddr_t)&addr, sizeof(addr), TRUE);
+ }
+ if (ret < 0)
+ return (ret);
+
+ wait_unit_ready(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */
+ waitfix_mmc(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */
+ return (ret);
+}
+
+static int
+send_opc_mmc(SCSI *usalp, caddr_t bp, int cnt, int doopc)
+{
+ int ret;
+
+ usalp->silent++;
+ ret = send_opc(usalp, bp, cnt, doopc);
+ usalp->silent--;
+
+ if (ret >= 0)
+ return (ret);
+
+ /* BEGIN CSTYLED */
+ /*
+ * Hack for a mysterioys drive ....
+ * Device type : Removable CD-ROM
+ * Version : 0
+ * Response Format: 1
+ * Vendor_info : 'RWD '
+ * Identifikation : 'RW2224 '
+ * Revision : '2.53'
+ * Device seems to be: Generic mmc CD-RW.
+ *
+ * Performing OPC...
+ * CDB: 54 01 00 00 00 00 00 00 00 00
+ * Sense Bytes: 70 00 06 00 00 00 00 0A 00 00 00 00 5A 03 00 00
+ * Sense Key: 0x6 Unit Attention, Segment 0
+ * Sense Code: 0x5A Qual 0x03 (operator selected write permit) Fru 0x0
+ * Sense flags: Blk 0 (not valid)
+ */
+ /* END CSTYLED */
+ if (usal_sense_key(usalp) == SC_UNIT_ATTENTION &&
+ usal_sense_code(usalp) == 0x5A &&
+ usal_sense_qual(usalp) == 0x03)
+ return (0);
+
+ /*
+ * Do not make the condition:
+ * "Power calibration area almost full" a fatal error.
+ * It just flags that we have a single and last chance to write now.
+ */
+ if ((usal_sense_key(usalp) == SC_RECOVERABLE_ERROR ||
+ usal_sense_key(usalp) == SC_MEDIUM_ERROR) &&
+ usal_sense_code(usalp) == 0x73 &&
+ usal_sense_qual(usalp) == 0x01)
+ return (0);
+
+ /*
+ * Send OPC is optional.
+ */
+ if (usal_sense_key(usalp) != SC_ILLEGAL_REQUEST) {
+ if (usalp->silent <= 0)
+ usal_printerr(usalp);
+ return (ret);
+ }
+ return (0);
+}
+
+static int
+opt1_mmc(SCSI *usalp, cdr_t *dp)
+{
+ int oflags = dp->cdr_dstat->ds_cdrflags;
+
+ if ((dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER) != 0) {
+ printf("Turning Audio Master Q. R. on\n");
+ if (set_audiomaster_yamaha(usalp, dp, TRUE) < 0)
+ return (-1);
+ if (!debug && lverbose <= 1)
+ dp->cdr_dstat->ds_cdrflags &= ~RF_PRATIP;
+ if (getdisktype_mmc(usalp, dp) < 0) {
+ dp->cdr_dstat->ds_cdrflags = oflags;
+ return (-1);
+ }
+ dp->cdr_dstat->ds_cdrflags = oflags;
+ if (oflags & RF_PRATIP) {
+ msf_t msf;
+ lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf);
+ printf("New start of lead in: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_first_leadin,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf);
+ printf("New start of lead out: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_maxblocks,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ }
+ }
+ if (mmc_isplextor(usalp)) {
+ int gcode;
+
+ if ((dp->cdr_flags & (CDR_SINGLESESS|CDR_HIDE_CDR)) != 0) {
+ if (ss_hide_plextor(usalp,
+ (dp->cdr_dstat->ds_cdrflags & RF_SINGLESESS) != 0,
+ (dp->cdr_dstat->ds_cdrflags & RF_HIDE_CDR) != 0) < 0)
+ return (-1);
+ }
+
+ if ((dp->cdr_flags & CDR_SPEEDREAD) != 0) {
+ if (speed_rd_plextor(usalp,
+ (dp->cdr_dstat->ds_cdrflags & RF_SPEEDREAD) != 0) < 0)
+ return (-1);
+ }
+
+ if ((dp->cdr_cmdflags & F_SETDROPTS) ||
+ (wm_base(dp->cdr_dstat->ds_wrmode) == WM_SAO) ||
+ (wm_base(dp->cdr_dstat->ds_wrmode) == WM_RAW))
+ gcode = do_gigarec_plextor(usalp);
+ else
+ gcode = gigarec_plextor(usalp, 0);
+ if (gcode != 0) {
+ msf_t msf;
+
+ dp->cdr_dstat->ds_first_leadin =
+ gigarec_mult(gcode, dp->cdr_dstat->ds_first_leadin);
+ dp->cdr_dstat->ds_maxblocks =
+ gigarec_mult(gcode, dp->cdr_dstat->ds_maxblocks);
+
+ if (oflags & RF_PRATIP) {
+ lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf);
+ printf("New start of lead in: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_first_leadin,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf);
+ printf("New start of lead out: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_maxblocks,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ }
+ }
+ }
+ return (0);
+}
+
+static int
+opt2_mmc(SCSI *usalp, cdr_t *dp)
+{
+ Uchar mode[0x100];
+ Uchar moder[0x100];
+ int len;
+ struct cd_mode_page_05 *mp;
+ struct ricoh_mode_page_30 *rp = NULL;
+ BOOL burnfree = FALSE;
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
+ return (-1);
+ if (len == 0)
+ return (-1);
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+
+ rp = get_justlink_ricoh(usalp, moder);
+
+ if (dp->cdr_cdcap->BUF != 0) {
+ burnfree = (mp->BUFE != 0);
+ } else if ((dp->cdr_flags & CDR_BURNFREE) != 0) {
+ burnfree = (rp && (rp->BUEFE != 0));
+ }
+
+ if (lverbose>2 && (dp->cdr_flags & CDR_BURNFREE) != 0)
+ printf("BURN-Free is %s.\n", burnfree?"ON":"OFF");
+
+ if (!burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) != 0) {
+ if(lverbose>2)
+ printf("Turning BURN-Free on\n");
+ burnfree = TRUE;
+ }
+ if (burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0) {
+ if(lverbose>2)
+ printf("Turning BURN-Free off\n");
+ burnfree = FALSE;
+ }
+ if (dp->cdr_cdcap->BUF != 0) {
+ mp->BUFE = burnfree?1:0;
+ }
+ else if ((dp->cdr_flags & CDR_BURNFREE) != 0) {
+
+ if (rp)
+ rp->BUEFE = burnfree?1:0;
+ }
+ if (rp) {
+ /*
+ * Clear Just-Link counter
+ */
+ i_to_2_byte(rp->link_counter, 0);
+ if (xdebug)
+ usal_prbytes("Mode Select Data ", moder, moder[0]+1);
+
+ if (!set_mode_params(usalp, "Ricoh Vendor Page", moder, moder[0]+1, 0, -1))
+ return (-1);
+ rp = get_justlink_ricoh(usalp, moder);
+ }
+
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1))
+ return (-1);
+
+ if (mmc_isplextor(usalp)) {
+ /*
+ * Clear Burn-Proof counter
+ */
+ usalp->silent++;
+ bpc_plextor(usalp, 1, NULL);
+ usalp->silent--;
+
+ do_varirec_plextor(usalp);
+ }
+
+ return (0);
+}
+
+static int
+opt1_mdvd(SCSI *usalp, cdr_t *dp)
+{
+ int oflags = dp->cdr_dstat->ds_cdrflags;
+
+ if ((dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER) != 0) {
+ printf("Turning Audio Master Q. R. on\n");
+ if (set_audiomaster_yamaha(usalp, dp, TRUE) < 0)
+ return (-1);
+ if (!debug && lverbose <= 1)
+ dp->cdr_dstat->ds_cdrflags &= ~RF_PRATIP;
+ if (getdisktype_mdvd(usalp, dp) < 0) {
+ dp->cdr_dstat->ds_cdrflags = oflags;
+ return (-1);
+ }
+ dp->cdr_dstat->ds_cdrflags = oflags;
+ if (oflags & RF_PRATIP) {
+ msf_t msf;
+ lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf);
+ printf("New start of lead in: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_first_leadin,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf);
+ printf("New start of lead out: %ld (%02d:%02d/%02d)\n",
+ (long)dp->cdr_dstat->ds_maxblocks,
+ msf.msf_min,
+ msf.msf_sec,
+ msf.msf_frame);
+ }
+ }
+ return (0);
+}
+
+static int
+scsi_sony_write(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 */)
+{
+ return (write_xg5(usalp, bp, sectaddr, size, blocks));
+}
+
+Uchar db2df[] = {
+ 0x00, /* 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 */
+ 0x10, /* 8 2048 bytes Mode 1 (ISO/IEC 10149) */
+ 0x30, /* 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_mmc(track_t *trackp, void *vcuep, BOOL needgap)
+{
+ int tracks = trackp->tracks;
+ int i;
+ struct mmc_cue **cuep = vcuep;
+ struct mmc_cue *cue;
+ struct mmc_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;
+ if (is_quadro(&trackp[i]))
+ ctl |= TM_QUADRO << 4;
+ df = db2df[trackp[i].dbtype & 0x0F];
+ if (trackp[i].tracktype == TOC_XA2 &&
+ trackp[i].sectype == (SECT_MODE_2_MIX|ST_MODE_RAW)) {
+ /*
+ * Hack for CUE with MODE2/CDI and
+ * trackp[i].dbtype == DB_RAW
+ */
+ df = 0x21;
+ }
+
+ 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);
+ }
+ }
+ if (i == 0) { /* Lead in */
+ df &= ~7; /* Mask off data size & nonRAW subch */
+ if (df < 0x10)
+ df |= 1;
+ else
+ df |= 4;
+ if (trackp[0].flags & TI_TEXT) /* CD-Text in Lead-in*/
+ df |= 0x40;
+ 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;
+ if (is_copy(&trackp[i]))
+ ctl |= TM_ALLOW_COPY << 4;
+ if (is_quadro(&trackp[i]))
+ ctl |= TM_QUADRO << 4;
+ df = db2df[trackp[tracks+1].dbtype & 0x0F];
+ if (trackp[i].tracktype == TOC_XA2 &&
+ trackp[i].sectype == (SECT_MODE_2_MIX|ST_MODE_RAW)) {
+ /*
+ * Hack for CUE with MODE2/CDI and
+ * trackp[i].dbtype == DB_RAW
+ */
+ df = 0x21;
+ }
+ df &= ~7; /* Mask off data size & nonRAW subch */
+ if (df < 0x10)
+ df |= 1;
+ else
+ df |= 4;
+ 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 mmc_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; /* XXX wie lead in */
+ cp->cs_tno = tno;
+ cp->cs_index = idx;
+ cp->cs_dataform = dataform; /* XXX wie lead in */
+ cp->cs_scms = scms;
+ cp->cs_min = mp->msf_min;
+ cp->cs_sec = mp->msf_sec;
+ cp->cs_frame = mp->msf_frame;
+}
+
+static int
+send_cue_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ struct mmc_cue *cp;
+ int ncue;
+ int ret;
+ Uint i;
+
+ 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);
+
+ usalp->silent++;
+ ret = send_cue_sheet(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 = send_cue_sheet(usalp, (caddr_t)cp, ncue*8);
+ if (ret < 0) {
+ errmsgno(EX_BAD,
+ "CUE sheet still not accepted. Please try to write in RAW (-raw96r) mode.\n");
+ }
+ free(cp);
+ }
+ return (ret);
+}
+
+static int
+stats_mmc(SCSI *usalp, cdr_t *dp)
+{
+ Uchar mode[256];
+ struct ricoh_mode_page_30 *rp;
+ UInt32_t count;
+
+ if (mmc_isplextor(usalp) && lverbose) {
+ int sels;
+ int maxs;
+ int lasts;
+
+ /*
+ * Run it in silent mode as old drives do not support it.
+ * As this function looks to be a part of the PowerRec
+ * features, we may want to check
+ * dp->cdr_flags & CDR_FORCESPEED
+ */
+ usalp->silent++;
+ if (get_speeds_plextor(usalp, &sels, &maxs, &lasts) >= 0) {
+ printf("Last selected write speed: %dx\n",
+ sels / 176);
+ printf("Max media write speed: %dx\n",
+ maxs / 176);
+ printf("Last actual write speed: %dx\n",
+ lasts / 176);
+ }
+ usalp->silent--;
+ }
+
+ if ((dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0)
+ return (0);
+
+ if (mmc_isplextor(usalp)) {
+ int i = 0;
+ int ret;
+
+ /*
+ * Read Burn-Proof counter
+ */
+ usalp->silent++;
+ ret = bpc_plextor(usalp, 2, &i);
+ usalp->silent--;
+ if (ret < 0)
+ return (-1);
+ count = i;
+ /*
+ * Clear Burn-Proof counter
+ */
+ bpc_plextor(usalp, 1, NULL);
+ } else {
+ rp = get_justlink_ricoh(usalp, mode);
+ if (rp)
+ count = a_to_u_2_byte(rp->link_counter);
+ else
+ return (-1);
+ }
+ if (lverbose) {
+ if (count == 0)
+ printf("BURN-Free was never needed.\n");
+ else
+ printf("BURN-Free was %d times used.\n",
+ (int)count);
+ }
+ return (0);
+}
+/*--------------------------------------------------------------------------*/
+static BOOL
+mmc_isplextor(SCSI *usalp)
+{
+ if (usalp->inq != NULL &&
+ strncmp(usalp->inq->vendor_info, "PLEXTOR", 7) == 0) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+static BOOL
+mmc_isyamaha(SCSI *usalp)
+{
+ if (usalp->inq != NULL &&
+ strncmp(usalp->inq->vendor_info, "YAMAHA", 6) == 0) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+static void
+do_varirec_plextor(SCSI *usalp)
+{
+ char *p;
+ int voff;
+
+ p = hasdrvopt(driveropts, "varirec=");
+ if (p == NULL || curspeed != 4) {
+ if (check_varirec_plextor(usalp) >= 0)
+ varirec_plextor(usalp, FALSE, 0);
+ } else {
+ if (*astoi(p, &voff) != '\0')
+ comerrno(EX_BAD,
+ "Bad varirec value '%s'.\n", p);
+ if (check_varirec_plextor(usalp) < 0)
+ comerrno(EX_BAD, "Drive does not support VariRec.\n");
+ varirec_plextor(usalp, TRUE, voff);
+ }
+}
+
+/*
+ * GigaRec value table
+ */
+struct gr {
+ Uchar val;
+ char vadd;
+ char *name;
+} gr[] = {
+ { 0x00, 0, "off", },
+ { 0x00, 0, "1.0", },
+ { 0x01, 2, "1.2", },
+ { 0x02, 3, "1.3", },
+ { 0x03, 4, "1.4", },
+ { 0x81, -2, "0.8", },
+ { 0x82, -3, "0.7", },
+ { 0x83, -4, "0.6", },
+ { 0x00, 0, NULL, },
+};
+
+static int
+do_gigarec_plextor(SCSI *usalp)
+{
+ char *p;
+ int val = 0; /* Make silly GCC happy */
+
+ p = hasdrvopt(driveropts, "gigarec=");
+ if (p == NULL) {
+ if (check_gigarec_plextor(usalp) >= 0)
+ gigarec_plextor(usalp, 0);
+ } else {
+ struct gr *gp = gr;
+
+ for (; gp->name != NULL; gp++) {
+ if (streql(p, gp->name)) {
+ val = gp->val;
+ break;
+ }
+ }
+ if (gp->name == NULL)
+ comerrno(EX_BAD,
+ "Bad gigarec value '%s'.\n", p);
+ if (check_gigarec_plextor(usalp) < 0)
+ comerrno(EX_BAD, "Drive does not support GigaRec.\n");
+ return (gigarec_plextor(usalp, val));
+ }
+ return (0);
+}
+
+static int
+drivemode_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ if (modeval == NULL) {
+ scmd->flags |= SCG_RECV_DATA;
+ scmd->addr = bp;
+ scmd->size = cnt;
+ } else {
+ scmd->cdb.g5_cdb.res = 0x08;
+ }
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xE9;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g1_cdb.addr[0] = modecode;
+ if (modeval)
+ movebytes(modeval, &scmd->cdb.g1_cdb.addr[1], 6);
+ else
+ i_to_2_byte(&scmd->cdb.g1_cdb.count[2], cnt);
+
+ usalp->cmdname = "plextor drive mode";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * #defines for drivemode_plextor()...
+ */
+#define MODE_CODE_SH 0x01 /* Mode code for Single Session & Hide-CDR */
+#define MB1_SS 0x01 /* Single Session Mode */
+#define MB1_HIDE_CDR 0x02 /* Hide CDR Media */
+
+#define MODE_CODE_VREC 0x02 /* Mode code for Vari Rec */
+
+#define MODE_CODE_GREC 0x04 /* Mode code for Giga Rec */
+
+#define MODE_CODE_SPEED 0xbb /* Mode code for Speed Read */
+#define MBbb_SPEAD_READ 0x01 /* Spead Read */
+ /* Danach Speed auf 0xFFFF 0xFFFF setzen */
+
+static int
+drivemode2_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ if (modeval == NULL) {
+ scmd->flags |= SCG_RECV_DATA;
+ scmd->addr = bp;
+ scmd->size = cnt;
+ } else {
+ scmd->cdb.g5_cdb.res = 0x08;
+ }
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xED;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g1_cdb.addr[0] = modecode;
+ if (modeval)
+ scmd->cdb.g5_cdb.reladr = *(char *)modeval != 0 ? 1 : 0;
+ else
+ i_to_2_byte(&scmd->cdb.g1_cdb.count[1], cnt);
+
+ usalp->cmdname = "plextor drive mode2";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+check_varirec_plextor(SCSI *usalp)
+{
+ int modecode = 2;
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ return (0);
+}
+
+static int
+check_gigarec_plextor(SCSI *usalp)
+{
+ int modecode = 4;
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ return (0);
+}
+
+static int
+varirec_plextor(SCSI *usalp, BOOL on, int val)
+{
+ int modecode = 2;
+ Uchar setmode[8];
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+
+ fillbytes(setmode, sizeof (setmode), '\0');
+ setmode[0] = on?1:0;
+ if (on) {
+ if (val < -2 || val > 2)
+ comerrno(EX_BAD, "Bad VariRec offset %d\n", val);
+ printf("Turning Varirec on.\n");
+ printf("Varirec offset is %d.\n", val);
+
+ if (val > 0) {
+ setmode[1] = val & 0x7F;
+ } else {
+ setmode[1] = (-val) & 0x7F;
+ setmode[1] |= 0x80;
+ }
+ }
+
+ if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0)
+ return (-1);
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0)
+ return (-1);
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+ return (0);
+}
+
+static int
+gigarec_plextor(SCSI *usalp, int val)
+{
+ int modecode = 4;
+ Uchar setmode[8];
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+
+ fillbytes(setmode, sizeof (setmode), '\0');
+ setmode[1] = val;
+
+ if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0)
+ return (-1);
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0)
+ return (-1);
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+ {
+ struct gr *gp = gr;
+
+ for (; gp->name != NULL; gp++) {
+ if (getmode[3] == gp->val)
+ break;
+ }
+ if (gp->name == NULL)
+ printf("Unknown GigaRec value 0x%X.\n", getmode[3]);
+ else
+ printf("GigaRec %sis %s.\n", gp->val?"value ":"", gp->name);
+ }
+ return (getmode[3]);
+}
+
+static Int32_t
+gigarec_mult(int code, Int32_t val)
+{
+ Int32_t add;
+ struct gr *gp = gr;
+
+ for (; gp->name != NULL; gp++) {
+ if (code == gp->val)
+ break;
+ }
+ if (gp->vadd == 0)
+ return (val);
+
+ add = val * gp->vadd / 10;
+ return (val + add);
+}
+
+static int
+check_ss_hide_plextor(SCSI *usalp)
+{
+ int modecode = 1;
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ return (getmode[2] & 0x03);
+}
+
+static int
+check_speed_rd_plextor(SCSI *usalp)
+{
+ int modecode = 0xBB;
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ return (getmode[2] & 0x01);
+}
+
+static int
+check_powerrec_plextor(SCSI *usalp)
+{
+ int modecode = 0;
+ Uchar getmode[8];
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (getmode[2] & 1)
+ return (1);
+
+ return (0);
+}
+
+static int
+ss_hide_plextor(SCSI *usalp, BOOL do_ss, BOOL do_hide)
+{
+ int modecode = 1;
+ Uchar setmode[8];
+ Uchar getmode[8];
+ BOOL is_ss;
+ BOOL is_hide;
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+
+ is_ss = (getmode[2] & MB1_SS) != 0;
+ is_hide = (getmode[2] & MB1_HIDE_CDR) != 0;
+
+ if (lverbose > 0) {
+ printf("Single session is %s.\n", is_ss ? "ON":"OFF");
+ printf("Hide CDR is %s.\n", is_hide ? "ON":"OFF");
+ }
+
+ fillbytes(setmode, sizeof (setmode), '\0');
+ setmode[0] = getmode[2]; /* Copy over old values */
+ if (do_ss >= 0) {
+ if (do_ss)
+ setmode[0] |= MB1_SS;
+ else
+ setmode[0] &= ~MB1_SS;
+ }
+ if (do_hide >= 0) {
+ if (do_hide)
+ setmode[0] |= MB1_HIDE_CDR;
+ else
+ setmode[0] &= ~MB1_HIDE_CDR;
+ }
+
+ if (do_ss >= 0 && do_ss != is_ss)
+ printf("Turning single session %s.\n", do_ss?"on":"off");
+ if (do_hide >= 0 && do_hide != is_hide)
+ printf("Turning hide CDR %s.\n", do_hide?"on":"off");
+
+ if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0)
+ return (-1);
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0)
+ return (-1);
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+ return (0);
+}
+
+static int
+speed_rd_plextor(SCSI *usalp, BOOL do_speedrd)
+{
+ int modecode = 0xBB;
+ Uchar setmode[8];
+ Uchar getmode[8];
+ BOOL is_speedrd;
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+
+ is_speedrd = (getmode[2] & MBbb_SPEAD_READ) != 0;
+
+ if (lverbose > 0)
+ printf("Speed-Read is %s.\n", is_speedrd ? "ON":"OFF");
+
+ fillbytes(setmode, sizeof (setmode), '\0');
+ setmode[0] = getmode[2]; /* Copy over old values */
+ if (do_speedrd >= 0) {
+ if (do_speedrd)
+ setmode[0] |= MBbb_SPEAD_READ;
+ else
+ setmode[0] &= ~MBbb_SPEAD_READ;
+ }
+
+ if (do_speedrd >= 0 && do_speedrd != is_speedrd)
+ printf("Turning Speed-Read %s.\n", do_speedrd?"on":"off");
+
+ if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0)
+ return (-1);
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0)
+ return (-1);
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+ /*
+ * Set current read speed to new max value.
+ */
+ if (do_speedrd >= 0 && do_speedrd != is_speedrd)
+ scsi_set_speed(usalp, 0xFFFF, -1, ROTCTL_CAV);
+
+ return (0);
+}
+
+static int
+powerrec_plextor(SCSI *usalp, BOOL do_powerrec)
+{
+ int modecode = 0;
+ Uchar setmode[8];
+ Uchar getmode[8];
+ BOOL is_powerrec;
+ int speed;
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ usalp->silent++;
+ if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) {
+ usalp->silent--;
+ return (-1);
+ }
+ usalp->silent--;
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+
+ is_powerrec = (getmode[2] & 1) != 0;
+
+ speed = a_to_u_2_byte(&getmode[4]);
+
+ if (lverbose > 0) {
+ printf("Power-Rec is %s.\n", is_powerrec ? "ON":"OFF");
+ printf("Power-Rec write speed: %dx (recommended)\n", speed / 176);
+ }
+
+ fillbytes(setmode, sizeof (setmode), '\0');
+ setmode[0] = getmode[2]; /* Copy over old values */
+ if (do_powerrec >= 0) {
+ if (do_powerrec)
+ setmode[0] |= 1;
+ else
+ setmode[0] &= ~1;
+ }
+
+ if (do_powerrec >= 0 && do_powerrec != is_powerrec)
+ printf("Turning Power-Rec %s.\n", do_powerrec?"on":"off");
+
+ if (drivemode2_plextor(usalp, NULL, 0, modecode, setmode) < 0)
+ return (-1);
+
+ fillbytes(getmode, sizeof (getmode), '\0');
+ if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0)
+ return (-1);
+
+ if (lverbose > 1)
+ usal_prbytes("Modes", getmode, sizeof (getmode));
+
+ return (0);
+}
+
+static int
+get_speeds_plextor(SCSI *usalp, int *selp, int *maxp, int *lastp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ char buf[10];
+ int i;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->flags |= SCG_RECV_DATA;
+ scmd->addr = buf;
+ scmd->size = sizeof (buf);
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xEB;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+
+ i_to_2_byte(&scmd->cdb.g1_cdb.count[1], sizeof (buf));
+
+ usalp->cmdname = "plextor get speedlist";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ i = a_to_u_2_byte(&buf[4]);
+ if (selp)
+ *selp = i;
+
+ i = a_to_u_2_byte(&buf[6]);
+ if (maxp)
+ *maxp = i;
+
+ i = a_to_u_2_byte(&buf[8]);
+ if (lastp)
+ *lastp = i;
+
+ return (0);
+}
+
+static int
+bpc_plextor(SCSI *usalp, int mode, int *bpp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ char buf[4];
+ int i;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->flags |= SCG_RECV_DATA;
+ scmd->addr = buf;
+ scmd->size = sizeof (buf);
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xF5;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+
+ scmd->cdb.g5_cdb.addr[1] = 0x08;
+ scmd->cdb.g5_cdb.addr[2] = mode;
+
+ i_to_2_byte(&scmd->cdb.g1_cdb.count[1], sizeof (buf));
+
+ usalp->cmdname = "plextor read bpc";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ if (usal_getresid(usalp) > 2)
+ return (0);
+
+ i = a_to_u_2_byte(buf);
+ if (bpp)
+ *bpp = i;
+
+ return (0);
+}
+
+static int
+set_audiomaster_yamaha(SCSI *usalp, cdr_t *dp, BOOL keep_mode)
+{
+ Uchar mode[0x100];
+ int len;
+ int ret = 0;
+ struct cd_mode_page_05 *mp;
+
+ if (xdebug && !keep_mode)
+ printf("Checking for Yamaha Audio Master feature: ");
+
+ /*
+ * Do not reset mp->test_write (-dummy) here.
+ */
+ deflt_writemodes_mmc(usalp, FALSE);
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x05, "CD write parameter",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ usalp->silent--;
+ return (-1);
+ }
+ if (len == 0) {
+ usalp->silent--;
+ return (-1);
+ }
+
+ mp = (struct cd_mode_page_05 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+#ifdef DEBUG
+ usal_prbytes("CD write parameter:", (Uchar *)mode, len);
+#endif
+
+ /*
+ * Do not set mp->test_write (-dummy) here. It should be set
+ * only at one place and only one time.
+ */
+ mp->BUFE = 0;
+
+ mp->write_type = 8;
+ mp->track_mode = 0;
+ mp->dbtype = DB_RAW;
+
+ if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1))
+ ret = -1;
+
+ /*
+ * Do not reset mp->test_write (-dummy) here.
+ */
+ if (!keep_mode || ret < 0)
+ deflt_writemodes_mmc(usalp, FALSE);
+ usalp->silent--;
+
+ return (ret);
+}
+
+struct
+ricoh_mode_page_30 *get_justlink_ricoh(SCSI *usalp, Uchar *mode)
+{
+ Uchar modec[0x100];
+ int len;
+ struct ricoh_mode_page_30 *mp;
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x30, "Ricoh Vendor Page", mode, modec, NULL, NULL, &len)) {
+ usalp->silent--;
+ return ((struct ricoh_mode_page_30 *)0);
+ }
+ usalp->silent--;
+
+ /*
+ * SCSI mode header + 6 bytes mode page 30.
+ * This is including the Burn-Free counter.
+ */
+ if (len < 10)
+ return ((struct ricoh_mode_page_30 *)0);
+
+ if (xdebug) {
+ fprintf(stderr, "Mode len: %d\n", len);
+ usal_prbytes("Mode Sense Data ", mode, len);
+ usal_prbytes("Mode Sence CData", modec, len);
+ }
+
+ mp = (struct ricoh_mode_page_30 *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ /*
+ * 6 bytes mode page 30.
+ * This is including the Burn-Free counter.
+ */
+ if ((len - ((Uchar *)mp - mode) -1) < 5)
+ return ((struct ricoh_mode_page_30 *)0);
+
+ if (xdebug) {
+ fprintf(stderr, "Burnfree counter: %d\n", a_to_u_2_byte(mp->link_counter));
+ }
+ return (mp);
+}
+
+static int
+force_speed_yamaha(SCSI *usalp, int readspeed, int writespeed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xBB;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+
+ if (readspeed < 0)
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], 0xFFFF);
+ else
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], readspeed);
+ if (writespeed < 0)
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xFFFF);
+ else
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], writespeed);
+
+ scmd->cdb.cmd_cdb[11] = 0x80;
+
+ usalp->cmdname = "yamaha force cd speed";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+static BOOL
+get_tattoo_yamaha(SCSI *usalp, BOOL print, Int32_t *irp, Int32_t *orp)
+{
+ Uchar mode[0x100];
+ int len;
+ UInt32_t ival;
+ UInt32_t oval;
+ Uchar *mp;
+
+ usalp->silent++;
+ if (!get_mode_params(usalp, 0x31, "Yamaha Tattoo Page", mode, NULL, NULL, NULL, &len)) {
+ usalp->silent--;
+ return (FALSE);
+ }
+ usalp->silent--;
+
+ /*
+ * SCSI mode header + 16 bytes mode page 31.
+ * This is including the Burn-Free counter.
+ */
+ if (len < 20)
+ return (FALSE);
+
+ mp = (Uchar *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ /*
+ * 10 bytes mode page 31.
+ * This is including the Burn-Free counter.
+ */
+ if ((len - ((Uchar *)mp - mode) -1) < 10)
+ return (FALSE);
+
+ ival = a_to_u_3_byte(&mp[4]);
+ oval = a_to_u_3_byte(&mp[7]);
+
+ if (irp)
+ *irp = ival;
+ if (orp)
+ *orp = oval;
+
+ if (print && ival > 0 && oval > 0) {
+ printf("DiskT@2 inner r: %d\n", (int)ival);
+ printf("DiskT@2 outer r: %d\n", (int)oval);
+ printf("DiskT@2 image size: 3744 x %d pixel.\n",
+ (int)(oval-ival)+1);
+ }
+
+ return (TRUE);
+}
+
+static int
+do_tattoo_yamaha(SCSI *usalp, FILE *f)
+{
+ Int32_t ival = 0;
+ Int32_t oval = 0;
+ Int32_t lines;
+ off_t fsize;
+ char *buf = usalp->bufptr;
+ long bufsize = usalp->maxbuf;
+ long nsecs;
+ long amt;
+
+ nsecs = bufsize / 2048;
+ bufsize = nsecs * 2048;
+
+ if (!get_tattoo_yamaha(usalp, FALSE, &ival, &oval)) {
+ errmsgno(EX_BAD, "Cannot get DiskT@2 info.\n");
+ return (-1);
+ }
+
+ if (ival == 0 || oval == 0) {
+ errmsgno(EX_BAD, "DiskT@2 info not valid.\n");
+ return (-1);
+ }
+
+ lines = oval - ival + 1;
+ fsize = filesize(f);
+ if ((fsize % 3744) != 0 || fsize < (lines*3744)) {
+ errmsgno(EX_BAD, "Illegal DiskT@2 file size.\n");
+ return (-1);
+ }
+ if (fsize > (lines*3744))
+ fsize = lines*3744;
+
+ if (lverbose)
+ printf("Starting to write DiskT@2 data.\n");
+ fillbytes(buf, bufsize, '\0');
+ if ((amt = fileread(f, buf, bufsize)) <= 0) {
+ errmsg("DiskT@2 file read error.\n");
+ return (-1);
+ }
+
+ if (yamaha_write_buffer(usalp, 1, 0, ival, amt/2048, buf, amt) < 0) {
+ errmsgno(EX_BAD, "DiskT@2 1st write error.\n");
+ return (-1);
+ }
+ amt = (amt+2047) / 2048 * 2048;
+ fsize -= amt;
+
+ while (fsize > 0) {
+ fillbytes(buf, bufsize, '\0');
+ if ((amt = fileread(f, buf, bufsize)) <= 0) {
+ errmsg("DiskT@2 file read error.\n");
+ return (-1);
+ }
+ amt = (amt+2047) / 2048 * 2048;
+ fsize -= amt;
+ if (yamaha_write_buffer(usalp, 1, 0, 0, amt/2048, buf, amt) < 0) {
+ errmsgno(EX_BAD, "DiskT@2 write error.\n");
+ return (-1);
+ }
+ }
+
+ if (yamaha_write_buffer(usalp, 1, 0, oval, 0, buf, 0) < 0) {
+ errmsgno(EX_BAD, "DiskT@2 final error.\n");
+ return (-1);
+ }
+
+ wait_unit_ready(usalp, 1000); /* Wait for DiskT@2 */
+ waitfix_mmc(usalp, 1000); /* Wait for DiskT@2 */
+
+ return (0);
+}
+
+/*
+ * Yamaha specific version of 'write buffer' that offers an additional
+ * Parameter Length 'parlen' parameter.
+ */
+static int
+yamaha_write_buffer(SCSI *usalp, int mode, int bufferid, long offset,
+ long parlen, void *buffer, long buflen)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ Uchar *CDB;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = buffer;
+ scmd->size = buflen;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x3B;
+
+ CDB = (Uchar *)scmd->cdb.cmd_cdb;
+ CDB[1] = mode & 7;
+ CDB[2] = bufferid;
+ i_to_3_byte(&CDB[3], offset);
+ i_to_3_byte(&CDB[6], parlen);
+
+ usalp->cmdname = "write_buffer";
+
+ if (usal_cmd(usalp) >= 0)
+ return (1);
+ return (0);
+}
+
+static int
+dvd_dual_layer_split(SCSI *usalp, cdr_t *dp, long tsize)
+{
+ unsigned char xb[12];
+ long l0_size;
+
+ /* Get the Layer 0 defined data zone*/
+ if (read_dvd_structure(usalp, (caddr_t)xb, 12, 0, 0, 0x20) >= 0) {
+ if ((xb[1] | xb[0] << 8) < 13) {
+ fprintf(stderr, "dvd_dual_layer_split: read_dvd_structure returns invalid data\n");
+ return 1;
+ }
+ if (xb[4] & 0x80) {
+ printf("L0 zone size already set\n");
+ return 1;
+ }
+ l0_size = xb[11] | xb[10] << 8 | xb[9] << 16 | xb[8] << 24;
+ if (tsize < l0_size) {
+ fprintf(stderr, "track size smaller than one layer, use --force to force burning.");
+ return 0;
+ }
+ printf("L0 size: %ld (track size %ld)\n", l0_size, tsize);
+ l0_size = tsize / 2;
+ l0_size = l0_size - 1 + 16 - (l0_size - 1) % 16;
+ printf("New L0 size: %ld\n", l0_size);
+
+ memset (xb, 0, sizeof(xb));
+ xb[1] = sizeof(xb) - 2;
+ xb[8] = l0_size >> 24;
+ xb[9] = l0_size >> 16;
+ xb[10] = l0_size >> 8;
+ xb[11] = l0_size;
+ if (send_dvd_structure(usalp, (caddr_t)xb, 12, 0, 0x20)) {
+ fprintf(stderr, "dvd_dual_layer_split: send_dvd_structure failed, could not set middle zone location.\n");
+ return 0;
+ }
+ }
+ return 1;
+}