diff options
Diffstat (limited to 'wodim/drv_7501.c')
-rw-r--r-- | wodim/drv_7501.c | 1030 |
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); +} |