summaryrefslogtreecommitdiff
path: root/wodim/drv_7501.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/drv_7501.c')
-rw-r--r--wodim/drv_7501.c1030
1 files changed, 1030 insertions, 0 deletions
diff --git a/wodim/drv_7501.c b/wodim/drv_7501.c
new file mode 100644
index 0000000..5083750
--- /dev/null
+++ b/wodim/drv_7501.c
@@ -0,0 +1,1030 @@
+/*
+ * 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_7501.c 1.16 05/05/16 Copyright 2003-2005 J. Schilling */
+/*
+ * Device driver for the Masushita CW-7501
+ *
+ * Copyright (c) 2003-2005 J. Schilling
+ *
+ * Mode Pages:
+ * 0x01 error recovery Seite 100
+ * 0x02 disconnect/reconnect Seite 107
+ * 0x0D CD-ROM device parameter Seite 110
+ * 0x0E CD-ROM Audio control Seite 112
+ * 0x20 Speed & Tray position Seite 115
+ * 0x21 Media catalog number Seite 124
+ * 0x22 ISRC Seite 125
+ * 0x23 Dummy/Write Information Seite 126
+ * 0x24 CD-R disk information Seite 127
+ */
+/*
+ * 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.
+ */
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+#include <mconfig.h>
+
+#include <stdio.h>
+#include <standard.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <errno.h>
+#include <strdefs.h>
+#include <timedefs.h>
+
+#include <utypes.h>
+#include <btorder.h>
+#include <intcvt.h>
+#include <schily.h>
+
+#include <usal/usalcmd.h>
+#include <usal/scsidefs.h>
+#include <usal/scsireg.h>
+#include <usal/scsitransp.h>
+
+#include <libport.h>
+
+#include "wodim.h"
+
+extern int silent;
+extern int debug;
+extern int verbose;
+extern int lverbose;
+extern int xdebug;
+
+#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
+
+struct cw7501_mode_page_20 { /* Speed control */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x02 = 2 Bytes */
+ Uchar speed;
+ Ucbit res : 7;
+ Ucbit traypos : 1;
+};
+
+#else /* Motorola byteorder */
+
+struct cw7501_mode_page_20 { /* Speed control */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x02 = 2 Bytes */
+ Uchar speed;
+ Ucbit traypos : 1;
+ Ucbit res : 7;
+};
+#endif
+
+#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
+
+struct cw7501_mode_page_21 { /* MCN */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x12 = 20 Bytes */
+ Ucbit control : 4;
+ Ucbit addr : 4;
+ Uchar res_3;
+ Uchar res_4;
+ Uchar mcn[15];
+};
+
+#else /* Motorola byteorder */
+
+struct cw7501_mode_page_21 { /* MCN */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x12 = 20 Bytes */
+ Ucbit addr : 4;
+ Ucbit control : 4;
+ Uchar res_3;
+ Uchar res_4;
+ Uchar mcn[15];
+};
+#endif
+
+
+#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
+
+struct cw7501_mode_page_22 { /* ISRC */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x12 = 20 Bytes */
+ Ucbit control : 4;
+ Ucbit addr : 4;
+ Uchar trackno;
+ Uchar res_4;
+ Uchar isrc[15];
+};
+
+#else /* Motorola byteorder */
+
+struct cw7501_mode_page_22 { /* ISRC */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x12 = 20 Bytes */
+ Ucbit addr : 4;
+ Ucbit control : 4;
+ Uchar trackno;
+ Uchar res_4;
+ Uchar isrc[15];
+};
+#endif
+
+#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
+
+struct cw7501_mode_page_23 { /* Dummy / Write information */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x02 = 2 Bytes */
+ Uchar res;
+ Ucbit autopg : 1;
+ Ucbit dummy : 1;
+ Ucbit res3_72 : 6;
+};
+
+#else /* Motorola byteorder */
+
+struct cw7501_mode_page_23 { /* Dummy / Write information */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x02 = 2 Bytes */
+ Uchar res;
+ Ucbit res3_72 : 6;
+ Ucbit dummy : 1;
+ Ucbit autopg : 1;
+};
+#endif
+
+struct cw7501_mode_page_24 { /* CD-R Disk information */
+ MP_P_CODE; /* parsave & pagecode */
+ Uchar p_len; /* 0x0A = 12 Bytes */
+ Uchar disktype;
+ Uchar res;
+ Uchar appl_code[4];
+ Uchar disk_id[4];
+};
+
+struct cw7501_mode_data {
+ struct scsi_mode_header header;
+ union cdd_pagex {
+ struct cw7501_mode_page_20 page20;
+ struct cw7501_mode_page_21 page21;
+ struct cw7501_mode_page_22 page22;
+ struct cw7501_mode_page_23 page23;
+ struct cw7501_mode_page_24 page24;
+ } pagex;
+};
+
+/*
+ * Mode for read track information
+ */
+#define TI_TRACKINFO_R 0
+#define TI_NWA 1
+#define TI_PMA 2
+#define TI_TRACKINFO 3
+
+struct cw7501_nwa {
+ Uchar nwa_length[2];
+ Uchar nwa_res;
+ Uchar nwa_trackno;
+ Uchar nwa_nwa[4];
+ Uchar nwa_freeblocks[4];
+};
+
+struct cw7501_cue {
+ Uchar cs_ctladr; /* CTL/ADR for this track */
+ Uchar cs_tno; /* This track number */
+ Uchar cs_index; /* Index within this track */
+ Uchar cs_dataform; /* Data form */
+ /* Bit 0..3 Physical Format */
+ /* Bit 4 Alt Copy (SCMS) */
+ /* Bit 5 SubC Audio + RAW96 sub */
+ Uchar cs_extension; /* Reserved or MCN/ISRC */
+ Uchar cs_min; /* Absolute time minutes */
+ Uchar cs_sec; /* Absolute time seconds */
+ Uchar cs_frame; /* Absolute time frames */
+};
+
+
+static int cw7501_attach(SCSI *usalp, cdr_t *dp);
+static int cw7501_init(SCSI *usalp, cdr_t *dp);
+static int cw7501_getdisktype(SCSI *usalp, cdr_t *dp);
+static int cw7501_speed_select(SCSI *usalp, cdr_t *dp, int *speedp);
+static int cw7501_next_wr_addr(SCSI *usalp, track_t *trackp, long *ap);
+static int cw7501_write(SCSI *usalp, caddr_t bp, long sectaddr, long size,
+ int blocks, BOOL islast);
+static int cw7501_write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_open_track(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_close_track(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_gen_cue(track_t *trackp, void *vcuep, BOOL needgap);
+static void fillcue(struct cw7501_cue *cp, int ca, int tno, int idx,
+ int dataform, int scms, msf_t *mp);
+static int cw7501_send_cue(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_fixate(SCSI *usalp, cdr_t *dp, track_t *trackp);
+static int cw7501_rezero(SCSI *usalp, int reset, int dwreset);
+static int cw7501_read_trackinfo(SCSI *usalp, Uchar *bp, int count,
+ int track, int mode);
+static int cw7501_write_dao(SCSI *usalp, Uchar *bp, int len, int disktype);
+static int cw7501_reserve_track(SCSI *usalp, unsigned long);
+static int cw7501_set_mode(SCSI *usalp, int phys_form, int control,
+ int subc, int alt, int trackno, int tindex,
+ int packet_size, int write_mode);
+static int cw7501_finalize(SCSI *usalp, int pad, int fixed);
+
+
+cdr_t cdr_cw7501 = {
+ 0, 0,
+ /*
+ * Prinzipiell geht auch: CDR_PACKET & CDR_SRAW96R
+ */
+ CDR_TAO|CDR_SAO|CDR_TRAYLOAD,
+ CDR_CDRW_NONE,
+ 2, 2,
+ "cw_7501",
+ "driver for Matsushita/Panasonic CW-7501",
+ 0,
+ (dstat_t *)0,
+ drive_identify,
+ cw7501_attach,
+ cw7501_init,
+ cw7501_getdisktype,
+ scsi_load,
+ scsi_unload,
+ buf_dummy, /* RD buffer cap not supp. */
+ cmd_dummy, /* recovery_needed */
+ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
+ cw7501_speed_select,
+ select_secsize,
+ cw7501_next_wr_addr,
+ cw7501_reserve_track,
+ cw7501_write,
+ cw7501_gen_cue,
+ cw7501_send_cue,
+ cw7501_write_leadin,
+ cw7501_open_track,
+ cw7501_close_track,
+ cw7501_open_session,
+ cmd_dummy, /* close seession */
+ cmd_dummy, /* abort */
+ read_session_offset,
+ cw7501_fixate,
+ cmd_dummy, /* stats */
+ blank_dummy,
+ format_dummy,
+ (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
+ cmd_dummy, /* opt1 */
+ cmd_dummy, /* opt2 */
+};
+
+static const char *sd_cw7501_error_str[] = {
+ "\100\201diagnostic failure on ROM", /* 40 81 */
+ "\100\202diagnostic failure on CPU internal RAM", /* 40 82 */
+ "\100\203diagnostic failure on BUFFER RAM", /* 40 83 */
+ "\100\204diagnostic failure on internal SCSI controller", /* 40 84 */
+ "\100\205diagnostic failure on system mechanism", /* 40 85 */
+
+ "\210\000Illegal Que Sheet (DAO parameter)", /* 88 00 */
+ "\211\000Inappropriate command", /* 89 00 */
+
+ "\250\000Audio Play operation Not in Progress", /* A8 00 */
+ "\251\000Buffer Overrun", /* A9 00 */
+
+ "\300\000Unrecordable Disk", /* C0 00 */
+ "\301\000Illegal Track Status", /* C1 00 */
+ "\302\000Reserved track Status", /* C2 00 */
+ "\304\000Illegal Reserve Length for Reserve Track Command", /* C4 00 */
+ "\304\001Illegal Data Form for Reserve Track Command", /* C4 01 */
+ "\304\002Unable to Reserve Track, Because Track Mode has been Changed", /* C4 02 */
+
+ "\305\000Buffer error during recording", /* C5 00 */
+ "\307\000Disk Style mismatch", /* C7 00 */
+ "\312\000Power Calibration error", /* CA 00 */
+ "\313\000Write error (Fatal Error/Time out)", /* CB 00 */
+ "\314\000Not enough space (Leadin/Leadout space)", /* CC 00 */
+ "\315\000No track present to finalize", /* CD 00 */
+ "\317\000Unable to recover damaged disk", /* CF 00 */
+
+ "\320\000PMA area full (1000 blocks)", /* D0 00 */
+ "\321\000PCA area full (100 counts)", /* D1 00 */
+ "\322\000Recovery failed", /* D2 00 */
+ "\323\000Recovery needed", /* D3 00 */
+ NULL
+};
+
+static int
+cw7501_attach(SCSI *usalp, cdr_t *dp)
+{
+ usal_setnonstderrs(usalp, sd_cw7501_error_str);
+ return (0);
+}
+
+static int
+cw7501_init(SCSI *usalp, cdr_t *dp)
+{
+ return (cw7501_speed_select(usalp, dp, NULL));
+}
+
+static int
+cw7501_getdisktype(SCSI *usalp, cdr_t *dp)
+{
+ Ulong maxb = 0;
+ Uchar buf[256];
+ int ret;
+ dstat_t *dsp = dp->cdr_dstat;
+
+ if (xdebug > 0) {
+ usalp->silent++;
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 0);
+ if (ret >= 0)
+ usal_prbytes("TI EXIST-R (0): ", buf, 32 -usal_getresid(usalp));
+
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 1);
+ if (ret >= 0)
+ usal_prbytes("TI NWA (1): ", buf, 32 -usal_getresid(usalp));
+
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 2);
+ if (ret >= 0)
+ usal_prbytes("TI PMA (2): ", buf, 32 -usal_getresid(usalp));
+
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+ ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 3);
+ if (ret >= 0)
+ usal_prbytes("TI EXIST-ROM (3): ", buf, 32 -usal_getresid(usalp));
+ usalp->silent--;
+ }
+
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+
+ usalp->silent++;
+ ret = cw7501_read_trackinfo(usalp, buf, 12, 0, TI_NWA);
+ if (ret < 0 &&
+ (dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == RF_WRITE) {
+
+ /*
+ * 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");
+ cw7501_rezero(usalp, 0, 1);
+ wait_unit_ready(usalp, 60);
+ ret = cw7501_read_trackinfo(usalp, buf, 12, 0, TI_NWA);
+ }
+ usalp->silent--;
+
+ if (ret >= 0) {
+ maxb = a_to_u_4_byte(&buf[8]);
+ if (maxb != 0)
+ maxb -= 150;
+ }
+ dsp->ds_maxblocks = maxb;
+
+ return (drive_getdisktype(usalp, dp));
+}
+
+
+static int
+cw7501_speed_select(SCSI *usalp, cdr_t *dp, int *speedp)
+{
+ struct scsi_mode_page_header *mp;
+ char mode[256];
+ int len = 20;
+ int page = 0x20;
+ struct cw7501_mode_page_20 *xp20;
+ struct cw7501_mode_data md;
+ int count;
+ int speed = 1;
+ BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;
+
+ if (speedp) {
+ speed = *speedp;
+ } else {
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, page, "Speed information",
+ (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ return (-1);
+ }
+ if (len == 0)
+ return (-1);
+
+ mp = (struct scsi_mode_page_header *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ xp20 = (struct cw7501_mode_page_20 *)mp;
+ speed = xp20->speed;
+ }
+
+ fillbytes((caddr_t)&md, sizeof (md), '\0');
+
+ count = sizeof (struct scsi_mode_header) +
+ sizeof (struct cw7501_mode_page_20);
+
+ md.pagex.page20.p_code = 0x20;
+ md.pagex.page20.p_len = 0x02;
+ md.pagex.page20.speed = speed;
+
+ if (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2) < 0)
+ return (-1);
+
+ fillbytes((caddr_t)&md, sizeof (md), '\0');
+
+ count = sizeof (struct scsi_mode_header) +
+ sizeof (struct cw7501_mode_page_23);
+
+ md.pagex.page23.p_code = 0x23;
+ md.pagex.page23.p_len = 0x02;
+ md.pagex.page23.dummy = dummy?1:0;
+
+ return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
+}
+
+static int
+cw7501_next_wr_addr(SCSI *usalp, track_t *trackp, long *ap)
+{
+ struct cw7501_nwa *nwa;
+ Uchar buf[256];
+ 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 0 (if the track hasn't been started yet and is invisible
+ */
+ nwa = (struct cw7501_nwa *)buf;
+
+ if (trackp != 0 && trackp->track > 0 && is_packet(trackp)) {
+ fillbytes((caddr_t)buf, sizeof (buf), '\0');
+
+ usalp->silent++;
+ result = cw7501_read_trackinfo(usalp, buf, sizeof (*nwa),
+ trackp->trackno,
+ TI_NWA);
+ usalp->silent--;
+ }
+
+ if (result < 0) {
+ if (cw7501_read_trackinfo(usalp, buf, sizeof (*nwa),
+ 0, TI_NWA) < 0)
+ return (-1);
+ }
+ if (usalp->verbose)
+ usal_prbytes("track info:", buf,
+ 12-usal_getresid(usalp));
+ next_addr = a_to_4_byte(&nwa->nwa_nwa);
+ /*
+ * XXX Für TAO definitiv notwendig.
+ * XXX ABhängig von Auto-Pregap?
+ */
+ /* XXX */ next_addr += 150;
+ if (ap)
+ *ap = next_addr;
+ return (0);
+}
+
+static int
+cw7501_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 */)
+{
+ if (lverbose > 1 && islast)
+ printf("\nWriting last record for this track.\n");
+
+ return (write_xg0(usalp, bp, 0, size, blocks));
+}
+
+static int
+cw7501_write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ Uint i;
+ long startsec = 0L;
+
+ 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);
+ }
+
+ /*
+ * Next writable address function does not work in DAO
+ * mode for this writer, so we just assume -150.
+ */
+ startsec = -150;
+ if (debug)
+ printf("SAO startsec: %ld\n", startsec);
+
+ if (trackp[0].flags & TI_TEXT) {
+ errmsgno(EX_BAD, "CD-Text unsupported in CW-7501 - ignoring.\n");
+ } else for (i = 1; i <= trackp->tracks; i++) {
+ trackp[i].trackstart += startsec +150;
+ }
+ }
+ return (0);
+}
+
+static Uchar db2phys[] = {
+ 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 */
+ 0x02, /* 8 2048 bytes Mode 1 (ISO/IEC 10149) */
+ 0x03, /* 9 2336 bytes Mode 2 (ISO/IEC 10149) */
+ 0xFF, /* 10 2048 bytes Mode 2 (CD-ROM XA form 1) */
+ 0x04, /* 11 2056 bytes Mode 2 (CD-ROM XA form 1) */
+ 0xFF, /* 12 2324 bytes Mode 2 (CD-ROM XA form 2) */
+ 0x08, /* 13 2332 bytes Mode 2 (CD-ROM XA 1/2+subhdr) */
+ 0xFF, /* 14 - Reserved */
+ 0xFF, /* 15 - Vendor specific */
+};
+
+static int
+cw7501_open_track(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ struct scsi_mode_page_header *mp;
+ Uchar mode[256];
+ int len = 0;
+ int page = 0x23;
+ struct cw7501_mode_page_23 *xp23;
+
+ if (!is_tao(trackp) && !is_packet(trackp)) {
+ if (trackp->pregapsize > 0 && (trackp->flags & TI_PREGAP) == 0) {
+ if (lverbose) {
+ printf("Writing pregap for track %d at %ld\n",
+ (int)trackp->trackno,
+ trackp->trackstart-trackp->pregapsize);
+ }
+ /*
+ * XXX Do we need to check isecsize too?
+ */
+ pad_track(usalp, dp, trackp,
+ trackp->trackstart-trackp->pregapsize,
+ (Llong)trackp->pregapsize*trackp->secsize,
+ FALSE, 0);
+ }
+ return (0);
+ }
+
+ if (select_secsize(usalp, trackp->secsize) < 0)
+ return (-1);
+
+ if (!get_mode_params(usalp, page, "Dummy/autopg information",
+ (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ return (-1);
+ }
+ if (len == 0)
+ return (-1);
+
+ mp = (struct scsi_mode_page_header *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ xp23 = (struct cw7501_mode_page_23 *)mp;
+ xp23->autopg = 1;
+ if (!set_mode_params(usalp, "Dummy/autopg page", mode, len, 0, trackp->secsize))
+ return (-1);
+
+ /*
+ * Set write modes for next track.
+ */
+ if (cw7501_set_mode(usalp, db2phys[trackp->dbtype & 0x0F],
+ st2mode[trackp->sectype&ST_MASK] | (is_copy(trackp) ? TM_ALLOW_COPY : 0),
+ 0, is_scms(trackp) ? 1 : 0,
+ trackp->trackno, 1, 0,
+ /* write mode TAO */ 0x01) < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+static int
+cw7501_close_track(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ if (!is_tao(trackp) && !is_packet(trackp)) {
+ return (0);
+ }
+ return (scsi_flush_cache(usalp, FALSE));
+}
+
+static int
+cw7501_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ struct cw7501_mode_data md;
+ int count;
+
+ if (select_secsize(usalp, 2048) < 0)
+ return (-1);
+
+ /*
+ * Disable Auto Pregap when writing in SAO mode.
+ */
+ if (!is_tao(trackp) && !is_packet(trackp)) {
+ struct scsi_mode_page_header *mp;
+ Uchar mode[256];
+ int len = 0;
+ int page = 0x23;
+ struct cw7501_mode_page_23 *xp23;
+
+ if (!get_mode_params(usalp, page, "Dummy/autopg information",
+ (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+ return (-1);
+ }
+ if (len == 0)
+ return (-1);
+
+ mp = (struct scsi_mode_page_header *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ xp23 = (struct cw7501_mode_page_23 *)mp;
+ xp23->autopg = 0;
+ if (!set_mode_params(usalp, "Dummy/autopg page", mode, len, 0, trackp->secsize))
+ return (-1);
+
+ return (0);
+ }
+
+ /*
+ * Set Disk Type and Disk ID.
+ */
+ fillbytes((caddr_t)&md, sizeof (md), '\0');
+
+ count = sizeof (struct scsi_mode_header) +
+ sizeof (struct cw7501_mode_page_24);
+
+ md.pagex.page24.p_code = 0x24;
+ md.pagex.page24.p_len = 0x0A;
+ md.pagex.page24.disktype = toc2sess[track_base(trackp)->tracktype & TOC_MASK];
+ i_to_4_byte(&md.pagex.page24.disk_id, 0x12345);
+
+ return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
+}
+
+static int
+cw7501_fixate(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ if (!is_tao(trackp) && !is_packet(trackp)) {
+ return (scsi_flush_cache(usalp, FALSE));
+ }
+ /*
+ * 0x00 Finalize Disk (not appendable)
+ * 0x01 Finalize Session (allow next session)
+ * 0x10 Finalize track (variable packet writing) - Must fluch cache before
+ */
+ return (cw7501_finalize(usalp, 0, (track_base(trackp)->tracktype & TOCF_MULTI) ? 0x01 : 0x00));
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int
+cw7501_gen_cue(track_t *trackp, void *vcuep, BOOL needgap)
+{
+ int tracks = trackp->tracks;
+ int i;
+ struct cw7501_cue **cuep = vcuep;
+ struct cw7501_cue *cue;
+ struct cw7501_cue *cp;
+ int ncue = 0;
+ int icue = 0;
+ int pgsize;
+ msf_t m;
+ int ctl;
+ int df;
+ int scms;
+
+ cue = malloc(1);
+
+ for (i = 0; i <= tracks; i++) {
+ ctl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
+ if (is_copy(&trackp[i]))
+ ctl |= TM_ALLOW_COPY << 4;
+ df = db2phys[trackp[i].dbtype & 0x0F];
+
+ 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 */
+ lba_to_msf(-150, &m);
+ cue = realloc(cue, ++ncue * sizeof (*cue));
+ cp = &cue[icue++];
+ fillcue(cp, ctl|0x01, i, 0, df, 0, &m);
+ } else {
+ scms = 0;
+
+ if (is_scms(&trackp[i]))
+ scms = 0x80;
+ pgsize = trackp[i].pregapsize;
+ if (pgsize == 0 && needgap)
+ pgsize++;
+ lba_to_msf(trackp[i].trackstart-pgsize, &m);
+ cue = realloc(cue, ++ncue * sizeof (*cue));
+ cp = &cue[icue++];
+ fillcue(cp, ctl|0x01, i, 0, df, scms, &m);
+
+ if (trackp[i].nindex == 1) {
+ lba_to_msf(trackp[i].trackstart, &m);
+ cue = realloc(cue, ++ncue * sizeof (*cue));
+ cp = &cue[icue++];
+ fillcue(cp, ctl|0x01, i, 1, df, scms, &m);
+ } else {
+ int idx;
+ long *idxlist;
+
+ ncue += trackp[i].nindex;
+ idxlist = trackp[i].tindex;
+ cue = realloc(cue, ncue * sizeof (*cue));
+
+ for (idx = 1; idx <= trackp[i].nindex; idx++) {
+ lba_to_msf(trackp[i].trackstart + idxlist[idx], &m);
+ cp = &cue[icue++];
+ fillcue(cp, ctl|0x01, i, idx, df, scms, &m);
+ }
+ }
+ }
+ }
+ /* Lead out */
+ ctl = (st2mode[trackp[tracks+1].sectype & ST_MASK]) << 4;
+ df = db2phys[trackp[tracks+1].dbtype & 0x0F];
+ 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 cw7501_cue *cp /* The target cue entry */,
+ int ca /* Control/adr for this entry */,
+ int tno /* Track number for this entry */,
+ int idx /* Index for this entry */,
+ int dataform /* Data format for this entry */,
+ int scms /* Serial copy management */,
+ msf_t *mp /* MSF value for this entry */)
+{
+ cp->cs_ctladr = ca;
+ if (tno <= 99)
+ cp->cs_tno = to_bcd(tno);
+ else
+ cp->cs_tno = tno;
+ cp->cs_index = to_bcd(idx);
+ if (scms != 0)
+ dataform |= 0x10;
+ cp->cs_dataform = dataform;
+ cp->cs_extension = 0;
+ cp->cs_min = to_bcd(mp->msf_min);
+ cp->cs_sec = to_bcd(mp->msf_sec);
+ cp->cs_frame = to_bcd(mp->msf_frame);
+}
+
+static int
+cw7501_send_cue(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ struct cw7501_cue *cp;
+ int ncue;
+ int ret;
+ Uint i;
+ struct timeval starttime;
+ struct timeval stoptime;
+ int disktype;
+
+ disktype = toc2sess[track_base(trackp)->tracktype & TOC_MASK];
+
+ for (i = 1; i <= trackp->tracks; i++) {
+ if (trackp[i].tracksize < (tsize_t)0) {
+ errmsgno(EX_BAD, "Track %d has unknown length.\n", i);
+ return (-1);
+ }
+ }
+ ncue = (*dp->cdr_gen_cue)(trackp, &cp, FALSE);
+
+ starttime.tv_sec = 0;
+ starttime.tv_usec = 0;
+ stoptime = starttime;
+ gettimeofday(&starttime, (struct timezone *)0);
+
+ usalp->silent++;
+ ret = cw7501_write_dao(usalp, (Uchar *)cp, ncue*8, disktype);
+ 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 = cw7501_write_dao(usalp, (Uchar *)cp, ncue*8, disktype);
+ free(cp);
+ }
+ if (ret >= 0 && lverbose) {
+ gettimeofday(&stoptime, (struct timezone *)0);
+ prtimediff("Write Lead-in time: ", &starttime, &stoptime);
+ }
+ return (ret);
+}
+
+/*--------------------------------------------------------------------------*/
+static int
+cw7501_rezero(SCSI *usalp, int reset, int dwreset)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)0;
+ scmd->size = 0;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_REZERO_UNIT;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[5] |= reset ? 0x80 : 0;
+ scmd->cdb.cmd_cdb[5] |= dwreset ? 0x40 : 0;
+
+ usalp->cmdname = "cw7501 rezero";
+
+ return (usal_cmd(usalp));
+}
+
+
+static int
+cw7501_read_trackinfo(SCSI *usalp, Uchar *bp, int count, int track, int mode)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t) scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)bp;
+ scmd->size = count;
+ scmd->flags = SCG_RECV_DATA | SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0xE9;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[6] = track;
+ g1_cdblen(&scmd->cdb.g1_cdb, count);
+ scmd->cdb.cmd_cdb[9] = (mode & 3) << 6;
+
+ usalp->cmdname = "cw7501 read_track_information";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+cw7501_write_dao(SCSI *usalp, Uchar *bp, int len, int disktype)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)bp;
+ scmd->size = len;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0xE6;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[2] = disktype;
+ g1_cdblen(&scmd->cdb.g1_cdb, len);
+
+ usalp->cmdname = "cw7501 write_dao";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * XXX CW-7501 also needs "control", so we need to make a different
+ * XXX driver interface.
+ */
+static int
+cw7501_reserve_track(SCSI *usalp, unsigned long len)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0xE7;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+/* scmd->cdb.cmd_cdb[2] = control & 0x0F;*/
+ i_to_4_byte(&scmd->cdb.cmd_cdb[5], len);
+
+ usalp->cmdname = "cw7501 reserve_track";
+
+ comerrno(EX_BAD, "Control (as in set mode) missing.\n");
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+static int
+cw7501_set_mode(SCSI *usalp, int phys_form, int control, int subc,
+ int alt, int trackno, int tindex, int packet_size,
+ int write_mode)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0xE2;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[2] = phys_form & 0x0F;
+ scmd->cdb.cmd_cdb[3] = (control & 0x0F) << 4;
+ scmd->cdb.cmd_cdb[3] |= subc ? 2 : 0;
+ scmd->cdb.cmd_cdb[3] |= alt ? 1 : 0;
+ scmd->cdb.cmd_cdb[4] = trackno;
+ scmd->cdb.cmd_cdb[5] = tindex;
+ i_to_3_byte(&scmd->cdb.cmd_cdb[6], packet_size);
+ scmd->cdb.cmd_cdb[9] = (write_mode & 0x03) << 6;
+
+ usalp->cmdname = "cw7501 set_mode";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+static int
+cw7501_finalize(SCSI *usalp, int pad, int fixed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 8 * 60; /* Needs up to 4 minutes */
+ scmd->cdb.g1_cdb.cmd = 0xE3;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[1] = pad ? 1 : 0;
+ scmd->cdb.cmd_cdb[8] = fixed & 0x03;
+
+ usalp->cmdname = "cw7501 finalize";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}